wee 0.7.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +96 -0
- data/README +2 -5
- data/examples/ObjectSpaceBrowser.rb +24 -42
- data/examples/ajax/ajax.js +444 -0
- data/examples/ajax/ajax.rb +31 -0
- data/examples/calculator.rb +1 -3
- data/examples/cc.rb +9 -29
- data/examples/live-update.rb +1 -1
- data/examples/test.rb +2 -2
- data/examples/window.rb +1 -1
- data/lib/wee.rb +1 -1
- data/lib/wee/abstractsession.rb +96 -0
- data/lib/wee/adaptors/fastcgi.rb +76 -0
- data/lib/wee/adaptors/webrick.rb +3 -3
- data/lib/wee/application.rb +7 -4
- data/lib/wee/core/callback.rb +2 -0
- data/lib/wee/core/component.rb +46 -24
- data/lib/wee/core/decoration.rb +5 -5
- data/lib/wee/core/presenter.rb +43 -27
- data/lib/wee/core/valueholder.rb +1 -1
- data/lib/wee/databases/og/scaffolder.rb +0 -1
- data/lib/wee/pageless/application.rb +8 -4
- data/lib/wee/pageless/request.rb +17 -5
- data/lib/wee/pageless/session.rb +38 -52
- data/lib/wee/renderer/html/brushes.rb +7 -1
- data/lib/wee/renderer/html/canvas.rb +1 -1
- data/lib/wee/request.rb +68 -7
- data/lib/wee/response.rb +2 -1
- data/lib/wee/session.rb +128 -129
- data/test/test_request.rb +31 -3
- metadata +30 -25
data/lib/wee/core/decoration.rb
CHANGED
@@ -44,8 +44,8 @@ class Wee::Decoration < Wee::Presenter
|
|
44
44
|
|
45
45
|
# Forwards method call to the next decoration in the chain.
|
46
46
|
|
47
|
-
def process_callbacks(
|
48
|
-
@owner.process_callbacks(
|
47
|
+
def process_callbacks(&block)
|
48
|
+
@owner.process_callbacks(&block)
|
49
49
|
end
|
50
50
|
|
51
51
|
# Forwards method call to the next decoration in the chain.
|
@@ -93,8 +93,8 @@ class Wee::Delegate < Wee::Decoration
|
|
93
93
|
# Forwards method to the corresponding top-level *chain* method of the
|
94
94
|
# _delegate_ component.
|
95
95
|
|
96
|
-
def process_callbacks(
|
97
|
-
@delegate.process_callbacks_chain(
|
96
|
+
def process_callbacks(&block)
|
97
|
+
@delegate.process_callbacks_chain(&block)
|
98
98
|
end
|
99
99
|
|
100
100
|
# Forwards method to the corresponding top-level *chain* method of the
|
@@ -128,7 +128,7 @@ class Wee::AnswerDecoration < Wee::Decoration
|
|
128
128
|
|
129
129
|
attr_accessor :on_answer
|
130
130
|
|
131
|
-
def process_callbacks(
|
131
|
+
def process_callbacks(&block)
|
132
132
|
args = catch(:wee_answer) { super; nil }
|
133
133
|
if args != nil
|
134
134
|
# return to the calling component
|
data/lib/wee/core/presenter.rb
CHANGED
@@ -75,30 +75,12 @@ class Wee::Presenter
|
|
75
75
|
|
76
76
|
# Process all callbacks specified for this presenter.
|
77
77
|
#
|
78
|
-
#
|
79
|
-
#
|
80
|
-
#
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
# [+callback_stream+]
|
85
|
-
# An object of class CallbackStream
|
86
|
-
|
87
|
-
def process_callbacks(callback_stream) # :yields:
|
88
|
-
# invoke input callbacks
|
89
|
-
callback_stream.with_callbacks_for(self, :input) { |callback, value|
|
90
|
-
callback.call(value)
|
91
|
-
}
|
92
|
-
|
93
|
-
# enable subclasses to add behaviour, e.g. a Component class will invoke
|
94
|
-
# process_callbacks_chain for each child in the block.
|
95
|
-
yield if block_given?
|
96
|
-
|
97
|
-
# invoke action callback. only the first action callback is invoked.
|
98
|
-
callback_stream.with_callbacks_for(self, :action) { |callback, value|
|
99
|
-
callback.call
|
100
|
-
throw :wee_back_to_session
|
101
|
-
}
|
78
|
+
# [+block+]
|
79
|
+
# Specifies the action to be taken (e.g. whether to invoke input or action
|
80
|
+
# callbacks).
|
81
|
+
|
82
|
+
def process_callbacks(&block)
|
83
|
+
block.call(self)
|
102
84
|
end
|
103
85
|
|
104
86
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
@@ -129,17 +111,51 @@ class Wee::Presenter
|
|
129
111
|
Wee::Session.current
|
130
112
|
end
|
131
113
|
|
114
|
+
# Send a premature response.
|
115
|
+
|
116
|
+
protected
|
117
|
+
|
118
|
+
def send_response(response)
|
119
|
+
throw :wee_send_response, response
|
120
|
+
end
|
121
|
+
|
122
|
+
# Call the block inside a rendering environment, then send the response prematurely.
|
123
|
+
|
124
|
+
def send_render_response(&block)
|
125
|
+
# Generate a response
|
126
|
+
response = Wee::GenericResponse.new('text/html', '')
|
127
|
+
|
128
|
+
# Get the current context we are in
|
129
|
+
context = session.current_context
|
130
|
+
|
131
|
+
# A rendering context is needed to use 'r' (if you want, you can simply
|
132
|
+
# omit this and just return the response with some html/xml filled in.
|
133
|
+
rendering_context = Wee::RenderingContext.new(
|
134
|
+
context.request,
|
135
|
+
context.response,
|
136
|
+
session.current_callbacks,
|
137
|
+
Wee::HtmlWriter.new(response.content))
|
138
|
+
|
139
|
+
with_renderer_for(rendering_context, &block)
|
140
|
+
|
141
|
+
send_response(response)
|
142
|
+
end
|
143
|
+
|
144
|
+
|
132
145
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
133
146
|
# :section: Properties
|
134
147
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
135
148
|
|
136
|
-
|
149
|
+
public
|
150
|
+
|
151
|
+
def properties() @__properties end
|
152
|
+
def properties=(props) @__properties = props end
|
137
153
|
|
138
154
|
# Returns an "owned" property.
|
139
155
|
|
140
156
|
def get_property(prop)
|
141
|
-
if
|
142
|
-
|
157
|
+
if self.properties
|
158
|
+
self.properties[prop]
|
143
159
|
else
|
144
160
|
nil
|
145
161
|
end
|
data/lib/wee/core/valueholder.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Implements a value holder. Useful for backtracking the reference assigned to
|
2
2
|
# an instance variable (not the object itself!). An example where this is used
|
3
|
-
# is the <tt>@
|
3
|
+
# is the <tt>@__decoration</tt> attribute of class Wee::Component.
|
4
4
|
|
5
5
|
class Wee::ValueHolder
|
6
6
|
attr_accessor :value
|
@@ -1,9 +1,13 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
|
1
3
|
class Wee::PagelessApplication < Wee::Application
|
2
4
|
def request_handler_expired(context)
|
3
|
-
context.response = Wee::RedirectResponse.new(context.request.
|
4
|
-
|
5
|
-
|
6
|
-
|
5
|
+
context.response = Wee::RedirectResponse.new(context.request.build_url(
|
6
|
+
:request_handler_id => nil,
|
7
|
+
:page_id => nil))
|
8
|
+
|
9
|
+
cookie = CGI::Cookie.new('SID', '')
|
10
|
+
cookie.expires = Time.at(0)
|
7
11
|
context.response.cookies << cookie
|
8
12
|
end
|
9
13
|
end
|
data/lib/wee/pageless/request.rb
CHANGED
@@ -1,15 +1,27 @@
|
|
1
1
|
class Wee::PagelessRequest < Wee::Request
|
2
|
+
private
|
2
3
|
|
3
|
-
def
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
def pageless?
|
5
|
+
true
|
6
|
+
end
|
7
|
+
|
8
|
+
def make_request_path(request_handler_id, page_id)
|
9
|
+
""
|
8
10
|
end
|
9
11
|
|
10
12
|
def parse_path
|
11
13
|
if sid = @cookies.find {|c| c.name == 'SID'}
|
12
14
|
@request_handler_id = sid.value
|
13
15
|
end
|
16
|
+
|
17
|
+
full_app_path = @path
|
18
|
+
|
19
|
+
if full_app_path == @app_path
|
20
|
+
@info = nil
|
21
|
+
elsif full_app_path[0, @app_path.size] == @app_path and full_app_path[@app_path.size] == ?/
|
22
|
+
@info = full_app_path[@app_path.size+1..-1]
|
23
|
+
else
|
24
|
+
raise "dispatched to wrong handler"
|
25
|
+
end
|
14
26
|
end
|
15
27
|
end
|
data/lib/wee/pageless/session.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'thread'
|
2
|
+
require 'cgi'
|
2
3
|
|
3
4
|
# A session class, which does not have a page-store and as such cannot
|
4
5
|
# backtrack.
|
@@ -10,77 +11,62 @@ class Wee::PagelessSession < Wee::Session
|
|
10
11
|
attr_accessor :callbacks
|
11
12
|
alias current_callbacks callbacks
|
12
13
|
|
13
|
-
def
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
block.call(self)
|
20
|
-
|
21
|
-
raise ArgumentError, "No root component specified" if @root_component.nil?
|
22
|
-
|
23
|
-
super()
|
24
|
-
ensure
|
25
|
-
Thread.current[:wee_session] = nil
|
14
|
+
def setup(&block)
|
15
|
+
with_session do
|
16
|
+
block.call(self) if block
|
17
|
+
raise ArgumentError, "No root component specified" if @root_component.nil?
|
18
|
+
end
|
26
19
|
end
|
27
20
|
|
28
|
-
|
29
|
-
p @context.request.fields if $DEBUG
|
30
|
-
|
31
|
-
if @context.request.fields.empty?
|
32
|
-
|
33
|
-
# No action/inputs were specified -> render page
|
34
|
-
#
|
35
|
-
# 1. Reset the action/input fields (as they are regenerated in the
|
36
|
-
# rendering process).
|
37
|
-
# 2. Render the page (respond).
|
38
|
-
# 3. Store the page back into the store
|
21
|
+
# The main routine where the request is processed.
|
39
22
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
else
|
23
|
+
def process_request
|
24
|
+
handle_existing_page
|
25
|
+
end
|
45
26
|
|
46
|
-
|
47
|
-
|
48
|
-
# We process the request and invoke actions/inputs. Then we generate a
|
49
|
-
# new page view.
|
27
|
+
def handle_existing_page
|
28
|
+
p @context.request.fields if $DEBUG
|
50
29
|
|
51
|
-
|
30
|
+
if @context.request.render?
|
31
|
+
handle_render_phase
|
32
|
+
else
|
33
|
+
handle_callback_phase
|
34
|
+
end
|
35
|
+
end
|
52
36
|
|
53
|
-
|
54
|
-
|
55
|
-
|
37
|
+
def handle_render_phase
|
38
|
+
new_callbacks = Wee::CallbackRegistry.new(Wee::SimpleIdGenerator.new)
|
39
|
+
respond(@context, new_callbacks) # render
|
40
|
+
self.callbacks = new_callbacks
|
41
|
+
end
|
56
42
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
}
|
43
|
+
def handle_callback_phase
|
44
|
+
# Actions/inputs were specified.
|
45
|
+
#
|
46
|
+
# We process the request and invoke actions/inputs. Then we generate a
|
47
|
+
# new page view.
|
63
48
|
|
64
|
-
|
65
|
-
|
66
|
-
else
|
67
|
-
handle_new_page_view(@context)
|
68
|
-
end
|
49
|
+
callback_stream = Wee::CallbackStream.new(self.callbacks, @context.request.fields)
|
50
|
+
send_response = invoke_callbacks(callback_stream)
|
69
51
|
|
70
|
-
|
52
|
+
post_callbacks_hook()
|
71
53
|
|
54
|
+
if send_response
|
55
|
+
set_response(@context, send_response) # @context.response = send_response
|
56
|
+
else
|
57
|
+
handle_new_page_view(@context)
|
58
|
+
end
|
72
59
|
end
|
73
60
|
|
74
61
|
private
|
75
62
|
|
76
63
|
def handle_new_page_view(context)
|
77
|
-
redirect_url = context.request.build_url
|
64
|
+
redirect_url = context.request.build_url
|
78
65
|
set_response(context, Wee::RedirectResponse.new(redirect_url))
|
79
66
|
end
|
80
67
|
|
81
68
|
def set_response(context, response)
|
82
|
-
|
83
|
-
response.cookies << WEBrick::Cookie.new('SID', self.id)
|
69
|
+
response.cookies << CGI::Cookie.new('SID', self.id)
|
84
70
|
response.header.delete('Expire')
|
85
71
|
response.header['Pragma'] = 'No-Cache'
|
86
72
|
super
|
@@ -151,6 +151,12 @@ class Brush::GenericTagBrush < Brush
|
|
151
151
|
onclick("javascript: document.location.href='#{ url }';")
|
152
152
|
end
|
153
153
|
|
154
|
+
def onclick_update(update_id, symbol=nil, *args, &block)
|
155
|
+
raise ArgumentError if symbol and block
|
156
|
+
url = @canvas.url_for_callback(to_callback(symbol, args, block))
|
157
|
+
onclick("javascript: new Ajax.Updater('#{ update_id }', '#{ url }', {method:'get'});")
|
158
|
+
end
|
159
|
+
|
154
160
|
# This method construct the css-class attribute by looking up the property
|
155
161
|
# from the current component.
|
156
162
|
|
@@ -455,7 +461,7 @@ class Brush::FormTag < Brush::GenericTagBrush
|
|
455
461
|
unless @attributes.has_key?('action')
|
456
462
|
req = @canvas.rendering_context.request
|
457
463
|
# TODO?
|
458
|
-
@attributes['action'] = req.build_url
|
464
|
+
@attributes['action'] = req.build_url
|
459
465
|
end
|
460
466
|
super
|
461
467
|
end
|
data/lib/wee/request.rb
CHANGED
@@ -6,12 +6,16 @@
|
|
6
6
|
|
7
7
|
class Wee::Request
|
8
8
|
|
9
|
-
DELIM = '
|
9
|
+
DELIM = '/___/'
|
10
10
|
|
11
11
|
attr_accessor :request_handler_id
|
12
12
|
attr_reader :page_id, :fields, :cookies
|
13
13
|
|
14
|
+
# The part of the URL that is user-defineable
|
15
|
+
attr_accessor :info
|
16
|
+
|
14
17
|
def initialize(app_path, path, headers, fields, cookies)
|
18
|
+
raise ArgumentError if app_path[-1] == ?/
|
15
19
|
@app_path, @path, @headers, @cookies = app_path, path, headers, cookies
|
16
20
|
parse_fields(fields)
|
17
21
|
parse_path
|
@@ -21,17 +25,51 @@ class Wee::Request
|
|
21
25
|
@app_path
|
22
26
|
end
|
23
27
|
|
24
|
-
|
28
|
+
# Is this an action request?
|
29
|
+
def action?
|
30
|
+
not render?
|
31
|
+
end
|
32
|
+
|
33
|
+
# Is this a render request?
|
34
|
+
def render?
|
35
|
+
self.fields.empty?
|
36
|
+
end
|
37
|
+
|
38
|
+
def build_url(hash={})
|
39
|
+
default = {
|
40
|
+
:request_handler_id => self.request_handler_id,
|
41
|
+
:page_id => self.page_id,
|
42
|
+
:info => self.info
|
43
|
+
}
|
44
|
+
hash = default.update(hash)
|
45
|
+
|
46
|
+
request_handler_id = hash[:request_handler_id]
|
47
|
+
page_id = hash[:page_id]
|
48
|
+
callback_id = hash[:callback_id]
|
49
|
+
info = hash[:info]
|
50
|
+
|
25
51
|
raise ArgumentError if request_handler_id.nil? and not page_id.nil?
|
52
|
+
if not pageless?
|
53
|
+
raise ArgumentError if page_id.nil? and not callback_id.nil?
|
54
|
+
end
|
26
55
|
|
27
|
-
|
56
|
+
# build request path, e.g. /___/req-id/page-id
|
57
|
+
req_path = make_request_path(request_handler_id, page_id)
|
28
58
|
|
29
|
-
|
59
|
+
# build the whole url
|
60
|
+
url = ""
|
30
61
|
url << @app_path
|
31
|
-
|
32
|
-
|
33
|
-
|
62
|
+
|
63
|
+
raise if url[-1] == ?/ # sanity check
|
64
|
+
|
65
|
+
if info
|
66
|
+
url << '/'
|
67
|
+
url << info
|
34
68
|
end
|
69
|
+
url << req_path
|
70
|
+
|
71
|
+
url << '/' if info.nil? and req_path.empty?
|
72
|
+
|
35
73
|
url << ('?' + callback_id) if callback_id
|
36
74
|
|
37
75
|
return url
|
@@ -39,6 +77,20 @@ class Wee::Request
|
|
39
77
|
|
40
78
|
private
|
41
79
|
|
80
|
+
def pageless?
|
81
|
+
false
|
82
|
+
end
|
83
|
+
|
84
|
+
def make_request_path(request_handler_id, page_id)
|
85
|
+
arr = [request_handler_id, page_id].compact
|
86
|
+
req_path =
|
87
|
+
if arr.empty?
|
88
|
+
""
|
89
|
+
else
|
90
|
+
DELIM + arr.join('/')
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
42
94
|
def parse_fields(fields)
|
43
95
|
fields ||= Hash.new
|
44
96
|
@fields = Hash.new
|
@@ -62,6 +114,15 @@ class Wee::Request
|
|
62
114
|
|
63
115
|
def parse_path
|
64
116
|
full_app_path, req_path = @path.split(DELIM, 2)
|
117
|
+
|
118
|
+
if full_app_path == @app_path
|
119
|
+
@info = nil
|
120
|
+
elsif full_app_path[0, @app_path.size] == @app_path and full_app_path[@app_path.size] == ?/
|
121
|
+
@info = full_app_path[@app_path.size+1..-1]
|
122
|
+
else
|
123
|
+
raise "dispatched to wrong handler"
|
124
|
+
end
|
125
|
+
|
65
126
|
@request_handler_id = @page_id = nil
|
66
127
|
@request_handler_id, @page_id = req_path.split('/', 2) if req_path
|
67
128
|
end
|