waves 0.7.3 → 0.7.5
Sign up to get free protection for your applications and to get access to all the features.
- data/app/Rakefile +11 -19
- data/app/bin/waves-console +3 -5
- data/app/bin/waves-server +3 -5
- data/app/configurations/development.rb.erb +19 -11
- data/app/configurations/mapping.rb.erb +4 -5
- data/app/configurations/production.rb.erb +18 -13
- data/app/{doc/EMTPY → controllers/.gitignore} +0 -0
- data/app/{public/css/EMPTY → doc/.gitignore} +0 -0
- data/app/{public/flash/EMPTY → helpers/.gitignore} +0 -0
- data/app/lib/application.rb.erb +4 -51
- data/app/{public/images/EMPTY → lib/tasks/.gitignore} +0 -0
- data/app/{public/javascript/EMPTY → log/.gitignore} +0 -0
- data/app/{tmp/sessions/EMPTY → 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/startup.rb +5 -0
- data/app/templates/layouts/default.mab +2 -2
- data/app/tmp/sessions/.gitignore +0 -0
- data/app/views/.gitignore +0 -0
- data/bin/waves +38 -27
- data/bin/waves-console +3 -25
- data/bin/waves-server +4 -45
- data/lib/commands/waves-console.rb +21 -0
- data/lib/commands/waves-server.rb +55 -0
- data/lib/controllers/base.rb +11 -0
- data/lib/controllers/mixin.rb +130 -102
- data/lib/dispatchers/base.rb +65 -50
- data/lib/dispatchers/default.rb +79 -52
- data/lib/foundations/default.rb +26 -0
- data/lib/foundations/simple.rb +30 -0
- data/lib/helpers/common.rb +60 -56
- data/lib/helpers/default.rb +13 -0
- data/lib/helpers/form.rb +39 -38
- data/lib/helpers/formatting.rb +11 -11
- data/lib/helpers/model.rb +12 -12
- data/lib/helpers/view.rb +13 -13
- data/lib/layers/default_errors.rb +29 -0
- data/lib/layers/mvc.rb +58 -0
- data/lib/layers/orm/active_record.rb +41 -0
- data/lib/layers/orm/active_record/migrations/empty.rb.erb +9 -0
- data/lib/layers/orm/active_record/tasks/schema.rb +30 -0
- data/lib/layers/orm/data_mapper.rb +42 -0
- data/lib/layers/orm/filebase.rb +22 -0
- data/lib/layers/orm/migration.rb +70 -0
- data/lib/layers/orm/sequel.rb +82 -0
- data/lib/layers/orm/sequel/migrations/empty.rb.erb +9 -0
- data/lib/layers/orm/sequel/tasks/schema.rb +24 -0
- data/lib/layers/simple.rb +39 -0
- data/lib/layers/simple_errors.rb +26 -0
- data/lib/mapping/mapping.rb +222 -120
- data/lib/mapping/pretty_urls.rb +42 -41
- data/lib/renderers/erubis.rb +54 -31
- data/lib/renderers/markaby.rb +28 -28
- data/lib/renderers/mixin.rb +49 -52
- data/lib/runtime/application.rb +66 -48
- data/lib/runtime/blackboard.rb +57 -0
- data/lib/runtime/configuration.rb +117 -101
- data/lib/runtime/console.rb +19 -20
- data/lib/runtime/debugger.rb +9 -0
- data/lib/runtime/logger.rb +43 -37
- data/lib/runtime/mime_types.rb +19 -19
- data/lib/runtime/request.rb +72 -46
- data/lib/runtime/response.rb +37 -37
- data/lib/runtime/response_mixin.rb +26 -23
- data/lib/runtime/response_proxy.rb +25 -24
- data/lib/runtime/server.rb +99 -80
- data/lib/runtime/session.rb +63 -53
- data/lib/tasks/cluster.rb +26 -0
- data/lib/tasks/gem.rb +31 -0
- data/lib/tasks/generate.rb +80 -0
- data/lib/utilities/hash.rb +22 -0
- data/lib/utilities/inflect.rb +194 -0
- data/lib/utilities/integer.rb +15 -12
- data/lib/utilities/kernel.rb +32 -32
- data/lib/utilities/module.rb +11 -4
- data/lib/utilities/object.rb +5 -5
- data/lib/utilities/proc.rb +10 -0
- data/lib/utilities/string.rb +44 -38
- data/lib/utilities/symbol.rb +4 -4
- data/lib/views/base.rb +9 -0
- data/lib/views/mixin.rb +91 -89
- data/lib/waves.rb +29 -9
- metadata +52 -26
- data/app/configurations/default.rb.erb +0 -8
- data/app/controllers/default.rb.erb +0 -29
- data/app/helpers/default.rb.erb +0 -13
- data/app/lib/startup.rb.erb +0 -3
- data/app/lib/tasks/cluster.rb +0 -24
- data/app/lib/tasks/generate.rb +0 -15
- data/app/lib/tasks/schema.rb +0 -29
- data/app/models/default.rb.erb +0 -13
- data/app/schema/migrations/templates/empty.rb.erb +0 -9
- data/app/views/default.rb.erb +0 -13
data/lib/runtime/session.rb
CHANGED
@@ -1,56 +1,66 @@
|
|
1
1
|
module Waves
|
2
|
-
|
2
|
+
|
3
3
|
# Encapsulates the session associated with a given request. A session has an expiration
|
4
|
-
# and path
|
5
|
-
#
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
4
|
+
# and path, which must be provided in a Waves::Configuration. Sensible defaults are defined
|
5
|
+
# in Waves::Configurations::Default
|
6
|
+
class Session
|
7
|
+
|
8
|
+
# Concoct a (probably) unique session id
|
9
|
+
def self.generate_session_id
|
10
|
+
# from Camping ...
|
11
|
+
chars = [*'A'..'Z'] + [*'0'..'9'] + [*'a'..'z']
|
12
|
+
(0..48).inject(''){|s,x| s+=chars[ rand(chars.length) ] }
|
13
|
+
end
|
14
|
+
|
15
|
+
# Create a new session object using the given request. This is not necessarily the
|
16
|
+
# same as constructing a new session. The session_id cookie for the request domain
|
17
|
+
# is used to store a session id. The actual session data will be stored in a directory
|
18
|
+
# specified by the application's configuration file.
|
19
|
+
def initialize( request )
|
20
|
+
@request = request
|
21
|
+
@data ||= ( File.exist?( session_path ) ? load_session : {} )
|
22
|
+
end
|
23
|
+
|
24
|
+
# Return the session data as a hash
|
25
|
+
def to_hash
|
26
|
+
@data.to_hash
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.base_path
|
30
|
+
Waves::Application.instance.config.session[:path]
|
31
|
+
end
|
32
|
+
|
33
|
+
# Save the session data. You shouldn't typically have to call this directly, since it
|
34
|
+
# is called by Waves::Response#finish.
|
35
|
+
def save
|
36
|
+
if @data && @data.length > 0
|
37
|
+
File.write( session_path, @data.to_yaml )
|
38
|
+
@request.response.set_cookie( 'session_id',
|
39
|
+
:value => session_id, :path => '/',
|
40
|
+
:expires => Time.now + Waves::Server.config.session[:duration] )
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Access a given data element of the session using the given key.
|
45
|
+
def [](key) ; @data[key] ; end
|
46
|
+
# Set the given data element of the session using the given key and value.
|
47
|
+
def []=(key,val) ; @data[key] = val ; end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def session_id
|
52
|
+
@session_id ||= ( @request.cookies['session_id'] || Waves::Session.generate_session_id )
|
53
|
+
end
|
54
|
+
|
55
|
+
def session_path
|
56
|
+
Waves::Session.base_path / session_id
|
57
|
+
end
|
58
|
+
|
59
|
+
def load_session
|
60
|
+
YAML.load( File.read( session_path ) )
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
55
65
|
end
|
56
|
-
|
66
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
namespace :cluster do
|
2
|
+
|
3
|
+
desc 'Start a cluster of waves applications.'
|
4
|
+
task :start do |task|
|
5
|
+
using_waves_src = defined?(WAVES) || ENV['WAVES'] || File.exist( File.dirname(__FILE__) / :waves )
|
6
|
+
script = using_waves_src ? :bin / 'waves-server' : 'waves-server'
|
7
|
+
( Waves::Console.config.ports || [ Waves::Console.config.port ] ).each do |port|
|
8
|
+
cmd = "#{script} -p #{port} -c #{ENV['mode']||'development'} -d"
|
9
|
+
puts cmd ; `#{cmd}`
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
desc 'Stop a cluster of waves applications.'
|
14
|
+
task :stop do |task|
|
15
|
+
Dir[ :log / '*.pid' ].each do |pidfile|
|
16
|
+
pid = File.read(pidfile).to_i
|
17
|
+
puts "Stopping process #{pid} ..."
|
18
|
+
Process.kill( 'INT', pid ) rescue nil
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
desc 'Restart a cluster of waves applications.'
|
23
|
+
task :restart => [ :stop, :start ] do |task|
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
data/lib/tasks/gem.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
namespace :gem do
|
2
|
+
desc "freeze a gem using gem=<gem name> [version=<gem version>]"
|
3
|
+
task :freeze do
|
4
|
+
raise "No gem specified" unless gem_name = ENV['gem']
|
5
|
+
|
6
|
+
require 'rubygems'
|
7
|
+
Gem.manage_gems
|
8
|
+
|
9
|
+
gem = (version = ENV['version']) ?
|
10
|
+
Gem.cache.search(gem_name, "= #{version}").first :
|
11
|
+
Gem.cache.search(gem_name).sort_by { |g| g.version }.last
|
12
|
+
|
13
|
+
version ||= gem.version.version rescue nil
|
14
|
+
|
15
|
+
target_dir = File.join(Waves::Configurations::Default.root, 'gems')
|
16
|
+
mkdir_p target_dir
|
17
|
+
sh "gem install #{gem_name} --version #{version} -i #{target_dir} --no-rdoc --no-ri"
|
18
|
+
|
19
|
+
puts "Unpacked #{gem_name} #{version} to '#{target_dir}'"
|
20
|
+
end
|
21
|
+
|
22
|
+
desc "unfreeze a gem using gem=<gem>"
|
23
|
+
task :unfreeze do
|
24
|
+
raise "No gem specified" unless gem_name = ENV['gem']
|
25
|
+
|
26
|
+
target_dir = File.join(Waves::Configurations::Default.root, 'gems')
|
27
|
+
ENV['GEM_HOME'] = target_dir # no install_dir option for gem uninstall
|
28
|
+
|
29
|
+
sh "gem uninstall #{gem_name}"
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
namespace :generate do
|
2
|
+
|
3
|
+
desc 'Generate a new controller, with name=<name>'
|
4
|
+
task :controller do |task|
|
5
|
+
name = ENV['name']
|
6
|
+
controller_name = name.camel_case
|
7
|
+
raise "Cannot generate Default yet" if controller_name == 'Default'
|
8
|
+
|
9
|
+
filename = File.expand_path "controllers/#{name}.rb"
|
10
|
+
if File.exist?(filename)
|
11
|
+
$stderr.puts "#{filename} already exists"
|
12
|
+
exit
|
13
|
+
end
|
14
|
+
|
15
|
+
controller = <<TEXT
|
16
|
+
module #{Waves.application.name}
|
17
|
+
module Controllers
|
18
|
+
class #{controller_name} < Default
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
TEXT
|
24
|
+
|
25
|
+
File.write( filename, controller )
|
26
|
+
end
|
27
|
+
|
28
|
+
desc 'Generate new view, with name=<name>'
|
29
|
+
task :view do |task|
|
30
|
+
name = ENV['name']
|
31
|
+
view_name = name.camel_case
|
32
|
+
raise "Cannot generate Default yet" if view_name == 'Default'
|
33
|
+
|
34
|
+
filename = File.expand_path "views/#{name}.rb"
|
35
|
+
if File.exist?(filename)
|
36
|
+
$stderr.puts "#{filename} already exists"
|
37
|
+
exit
|
38
|
+
end
|
39
|
+
|
40
|
+
view = <<TEXT
|
41
|
+
module #{Waves.application.name}
|
42
|
+
module Views
|
43
|
+
class #{view_name} < Default
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
TEXT
|
49
|
+
|
50
|
+
File.write( filename, view )
|
51
|
+
end
|
52
|
+
|
53
|
+
desc 'Generate a new helper, with name=<name>'
|
54
|
+
task :helper do |task|
|
55
|
+
name = ENV['name']
|
56
|
+
helper_name = name.camel_case
|
57
|
+
raise "Cannot generate Default yet" if helper_name == 'Default'
|
58
|
+
|
59
|
+
filename = File.expand_path "helpers/#{name}.rb"
|
60
|
+
if File.exist?(filename)
|
61
|
+
$stderr.puts "#{filename} already exists"
|
62
|
+
exit
|
63
|
+
end
|
64
|
+
|
65
|
+
helper = <<TEXT
|
66
|
+
module #{Waves.application.name}
|
67
|
+
module Helpers
|
68
|
+
module #{helper_name}
|
69
|
+
include Waves::Helpers::Default
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
TEXT
|
75
|
+
|
76
|
+
File.write( filename, helper )
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class Hash
|
2
|
+
|
3
|
+
def stringify_keys
|
4
|
+
inject({}) do |options, (key, value)|
|
5
|
+
options[key.to_s] = value
|
6
|
+
options
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
# Destructively convert all keys to symbols.
|
11
|
+
def symbolize_keys!
|
12
|
+
keys.each do |key|
|
13
|
+
unless key.is_a?(Symbol)
|
14
|
+
self[key.to_sym] = self[key]
|
15
|
+
delete(key)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,194 @@
|
|
1
|
+
# Much love to Facets (more specifically English) for this module
|
2
|
+
# http://english.rubyforge.org/
|
3
|
+
# changed slightly in the hopes of one day implementing a different set
|
4
|
+
# of rules for different languages
|
5
|
+
# NOTE: this is NOT implemented yet.
|
6
|
+
# plural and singular work directly with the English class
|
7
|
+
|
8
|
+
module Inflect # :nodoc:
|
9
|
+
module InflectorMethods
|
10
|
+
|
11
|
+
# Define a general exception.
|
12
|
+
def word(singular, plural=nil)
|
13
|
+
plural = singular unless plural
|
14
|
+
singular_word(singular, plural)
|
15
|
+
plural_word(singular, plural)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Define a singularization exception.
|
19
|
+
def singular_word(singular, plural)
|
20
|
+
@singular_of[plural] = singular
|
21
|
+
end
|
22
|
+
|
23
|
+
# Define a pluralization exception.
|
24
|
+
def plural_word(singular, plural)
|
25
|
+
@plural_of[singular] = plural
|
26
|
+
end
|
27
|
+
|
28
|
+
# Define a general rule.
|
29
|
+
def rule(singular, plural)
|
30
|
+
singular_rule(singular, plural)
|
31
|
+
plural_rule(singular, plural)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Define a singularization rule.
|
35
|
+
def singular_rule(singular, plural)
|
36
|
+
@singular_rules << [singular, plural]
|
37
|
+
end
|
38
|
+
|
39
|
+
# Define a plurualization rule.
|
40
|
+
def plural_rule(singular, plural)
|
41
|
+
@plural_rules << [singular, plural]
|
42
|
+
end
|
43
|
+
|
44
|
+
# Read prepared singularization rules.
|
45
|
+
def singularization_rules
|
46
|
+
return @singularization_rules if @singularization_rules
|
47
|
+
sorted = @singular_rules.sort_by{ |s, p| "#{p}".size }.reverse
|
48
|
+
@singularization_rules = sorted.collect do |s, p|
|
49
|
+
[ /#{p}$/, "#{s}" ]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Read prepared pluralization rules.
|
54
|
+
def pluralization_rules
|
55
|
+
return @pluralization_rules if @pluralization_rules
|
56
|
+
sorted = @plural_rules.sort_by{ |s, p| "#{s}".size }.reverse
|
57
|
+
@pluralization_rules = sorted.collect do |s, p|
|
58
|
+
[ /#{s}$/, "#{p}" ]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
#
|
63
|
+
def plural_of
|
64
|
+
@plural_of
|
65
|
+
end
|
66
|
+
|
67
|
+
#
|
68
|
+
def singular_of
|
69
|
+
@singular_of
|
70
|
+
end
|
71
|
+
|
72
|
+
# Convert an English word from plurel to singular.
|
73
|
+
#
|
74
|
+
# "boys".singular #=> boy
|
75
|
+
# "tomatoes".singular #=> tomato
|
76
|
+
#
|
77
|
+
def singular(word)
|
78
|
+
if result = singular_of[word]
|
79
|
+
return result.dup
|
80
|
+
end
|
81
|
+
result = word.dup
|
82
|
+
singularization_rules.each do |(match, replacement)|
|
83
|
+
break if result.gsub!(match, replacement)
|
84
|
+
end
|
85
|
+
return result
|
86
|
+
end
|
87
|
+
|
88
|
+
# Convert an English word from singular to plurel.
|
89
|
+
#
|
90
|
+
# "boy".plural #=> boys
|
91
|
+
# "tomato".plural #=> tomatoes
|
92
|
+
#
|
93
|
+
def plural(word)
|
94
|
+
if result = plural_of[word]
|
95
|
+
return result.dup
|
96
|
+
end
|
97
|
+
#return self.dup if /s$/ =~ self # ???
|
98
|
+
result = word.dup
|
99
|
+
pluralization_rules.each do |(match, replacement)|
|
100
|
+
break if result.gsub!(match, replacement)
|
101
|
+
end
|
102
|
+
return result
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
class English # :nodoc:
|
107
|
+
@singular_of = {}
|
108
|
+
@plural_of = {}
|
109
|
+
|
110
|
+
@singular_rules = []
|
111
|
+
@plural_rules = []
|
112
|
+
|
113
|
+
class << self
|
114
|
+
include InflectorMethods
|
115
|
+
end
|
116
|
+
|
117
|
+
# One argument means singular and plural are the same.
|
118
|
+
word 'equipment'
|
119
|
+
word 'information'
|
120
|
+
word 'money'
|
121
|
+
word 'species'
|
122
|
+
word 'series'
|
123
|
+
word 'fish'
|
124
|
+
word 'sheep'
|
125
|
+
word 'moose'
|
126
|
+
word 'hovercraft'
|
127
|
+
|
128
|
+
# Two arguments defines a singular and plural exception.
|
129
|
+
word 'Swiss' , 'Swiss'
|
130
|
+
word 'life' , 'lives'
|
131
|
+
word 'wife' , 'wives'
|
132
|
+
word 'virus' , 'viri'
|
133
|
+
word 'octopus' , 'octopi'
|
134
|
+
word 'cactus' , 'cacti'
|
135
|
+
word 'goose' , 'geese'
|
136
|
+
word 'criterion' , 'criteria'
|
137
|
+
word 'alias' , 'aliases'
|
138
|
+
word 'status' , 'statuses'
|
139
|
+
word 'axis' , 'axes'
|
140
|
+
word 'crisis' , 'crises'
|
141
|
+
word 'testis' , 'testes'
|
142
|
+
word 'child' , 'children'
|
143
|
+
word 'person' , 'people'
|
144
|
+
word 'potato' , 'potatoes'
|
145
|
+
word 'tomato' , 'tomatoes'
|
146
|
+
word 'buffalo' , 'buffaloes'
|
147
|
+
word 'torpedo' , 'torpedoes'
|
148
|
+
word 'quiz' , 'quizes'
|
149
|
+
word 'matrix' , 'matrices'
|
150
|
+
word 'vertex' , 'vetices'
|
151
|
+
word 'index' , 'indices'
|
152
|
+
word 'ox' , 'oxen'
|
153
|
+
word 'mouse' , 'mice'
|
154
|
+
word 'louse' , 'lice'
|
155
|
+
word 'thesis' , 'theses'
|
156
|
+
word 'thief' , 'thieves'
|
157
|
+
word 'analysis' , 'analyses'
|
158
|
+
|
159
|
+
# One-way singularization exception (convert plural to singular).
|
160
|
+
singular_word 'cactus', 'cacti'
|
161
|
+
|
162
|
+
# General rules.
|
163
|
+
rule 'hive' , 'hives'
|
164
|
+
rule 'rf' , 'rves'
|
165
|
+
rule 'af' , 'aves'
|
166
|
+
rule 'ero' , 'eroes'
|
167
|
+
rule 'man' , 'men'
|
168
|
+
rule 'ch' , 'ches'
|
169
|
+
rule 'sh' , 'shes'
|
170
|
+
rule 'ss' , 'sses'
|
171
|
+
rule 'ta' , 'tum'
|
172
|
+
rule 'ia' , 'ium'
|
173
|
+
rule 'ra' , 'rum'
|
174
|
+
rule 'ay' , 'ays'
|
175
|
+
rule 'ey' , 'eys'
|
176
|
+
rule 'oy' , 'oys'
|
177
|
+
rule 'uy' , 'uys'
|
178
|
+
rule 'y' , 'ies'
|
179
|
+
rule 'x' , 'xes'
|
180
|
+
rule 'lf' , 'lves'
|
181
|
+
rule 'us' , 'uses'
|
182
|
+
rule '' , 's'
|
183
|
+
|
184
|
+
# One-way singular rules.
|
185
|
+
singular_rule 'of' , 'ofs' # proof
|
186
|
+
singular_rule 'o' , 'oes' # hero, heroes
|
187
|
+
singular_rule 'f' , 'ves'
|
188
|
+
|
189
|
+
# One-way plural rules.
|
190
|
+
plural_rule 'fe' , 'ves' # safe, wife
|
191
|
+
plural_rule 's' , 'ses'
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|