wee 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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(callback_stream)
48
- @owner.process_callbacks(callback_stream)
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(callback_stream)
97
- @delegate.process_callbacks_chain(callback_stream)
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(callback_stream)
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
@@ -75,30 +75,12 @@ class Wee::Presenter
75
75
 
76
76
  # Process all callbacks specified for this presenter.
77
77
  #
78
- # At first, this method invokes all input callbacks of this presenter, then
79
- # it calls the block if one was given (used by subclasses). Finally, the
80
- # action callback is invoked (there's only one per request).
81
- #
82
- # NOTE: Input callbacks should never call other components!
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
- attr_accessor :properties
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 @properties
142
- @properties[prop]
157
+ if self.properties
158
+ self.properties[prop]
143
159
  else
144
160
  nil
145
161
  end
@@ -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>@decoration</tt> attribute of class Wee::Component.
3
+ # is the <tt>@__decoration</tt> attribute of class Wee::Component.
4
4
 
5
5
  class Wee::ValueHolder
6
6
  attr_accessor :value
@@ -5,7 +5,6 @@ class OgScaffolder < Wee::Component
5
5
  def initialize(domain_class)
6
6
  super()
7
7
  @domain_class = domain_class
8
- # DON'T use @properties here as it is already used by Wee
9
8
  @props = @domain_class.__props.reject {|a| a.name == 'oid'}
10
9
  end
11
10
 
@@ -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.application_path)
4
- # TODO: depends on WEBrick
5
- cookie = WEBrick::Cookie.new('SID', '')
6
- cookie.max_age = 0
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
@@ -1,15 +1,27 @@
1
1
  class Wee::PagelessRequest < Wee::Request
2
+ private
2
3
 
3
- def build_url(request_handler_id=nil, page_id=nil, callback_id=nil)
4
- url = ""
5
- url << @app_path
6
- url << ('?' + callback_id) if callback_id
7
- return url
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
@@ -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 initialize(&block)
14
- Thread.current[:wee_session] = self
15
-
16
- # to serialize the requests we need a mutex
17
- @mutex = Mutex.new
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
- def process_request
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
- new_callbacks = Wee::CallbackRegistry.new(Wee::SimpleIdGenerator.new)
41
- respond(@context, new_callbacks) # render
42
- self.callbacks = new_callbacks
43
-
44
- else
23
+ def process_request
24
+ handle_existing_page
25
+ end
45
26
 
46
- # Actions/inputs were specified.
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
- callback_stream = Wee::CallbackStream.new(self.callbacks, @context.request.fields)
30
+ if @context.request.render?
31
+ handle_render_phase
32
+ else
33
+ handle_callback_phase
34
+ end
35
+ end
52
36
 
53
- if callback_stream.all_of_type(:action).size > 1
54
- raise "Not allowed to specify more than one action callback"
55
- end
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
- live_update_response = catch(:wee_live_update) {
58
- catch(:wee_back_to_session) {
59
- @root_component.process_callbacks_chain(callback_stream)
60
- }
61
- nil
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
- if live_update_response
65
- @context.response = live_update_response
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
- end
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(context.request.request_handler_id, nil)
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
- # TODO: depends on WEBrick!
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(req.request_handler_id, req.page_id)
464
+ @attributes['action'] = req.build_url
459
465
  end
460
466
  super
461
467
  end
@@ -76,7 +76,7 @@ class HtmlCanvas < Canvas
76
76
 
77
77
  def url_for_callback_id(callback_id)
78
78
  req = self.rendering_context.request
79
- url = req.build_url(req.request_handler_id, req.page_id, callback_id)
79
+ url = req.build_url(:callback_id => callback_id)
80
80
  return url
81
81
  end
82
82
 
@@ -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
- def build_url(request_handler_id=nil, page_id=nil, callback_id=nil)
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
- arr = [request_handler_id, page_id].compact
56
+ # build request path, e.g. /___/req-id/page-id
57
+ req_path = make_request_path(request_handler_id, page_id)
28
58
 
29
- url = ""
59
+ # build the whole url
60
+ url = ""
30
61
  url << @app_path
31
- unless arr.empty?
32
- url << '/' if url[-1,1] != '/' # /appXXX -> /app/XXX
33
- url << (DELIM + arr.join('/'))
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