wee 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/wee/holder.rb ADDED
@@ -0,0 +1,14 @@
1
+ class Wee::ValueHolder
2
+ attr_accessor :value
3
+
4
+ def initialize(value=nil)
5
+ @value = value
6
+ end
7
+ end
8
+
9
+ class Wee::StateHolder < Wee::ValueHolder
10
+ def initialize(value)
11
+ super
12
+ Wee::Session.current.state_registry << self
13
+ end
14
+ end
@@ -0,0 +1,379 @@
1
+ module Wee
2
+
3
+ class Canvas
4
+ def initialize
5
+ @parent_brush = nil
6
+ @current_brush = nil
7
+ end
8
+
9
+ def set_brush(brush)
10
+ # tell previous brush to finish
11
+ @current_brush.close if @current_brush
12
+
13
+ brush.parent = @parent_brush
14
+ brush.canvas = self
15
+ @current_brush = brush
16
+
17
+ return brush
18
+ end
19
+
20
+ def nest(&block)
21
+ @parent_brush = @current_brush
22
+ @current_brush = nil
23
+ block.call
24
+ @current_brush.close if @current_brush
25
+ @parent_brush = @parent_brush.parent
26
+ end
27
+ end
28
+
29
+ class HtmlCanvas < Canvas
30
+ attr_reader :context # the current Wee::RenderingContext
31
+ attr_reader :document
32
+ attr_accessor :current_component
33
+
34
+ def initialize(rendering_context)
35
+ @context = rendering_context
36
+ @document = rendering_context.document
37
+ end
38
+
39
+ def table(*args, &block)
40
+ handle(Brush::TableTag.new, *args, &block)
41
+ end
42
+
43
+ def table_row(*args, &block)
44
+ handle(Brush::TableRowTag.new, *args, &block)
45
+ end
46
+
47
+ def table_data(*args, &block)
48
+ handle(Brush::TableDataTag.new, *args, &block)
49
+ end
50
+
51
+ def table_header(*args, &block)
52
+ handle(Brush::TableHeaderTag.new, *args, &block)
53
+ end
54
+
55
+ def form(*args, &block)
56
+ handle(Brush::FormTag.new, *args, &block)
57
+ end
58
+
59
+ def input(*args, &block)
60
+ handle(Brush::InputTag.new, *args, &block)
61
+ end
62
+
63
+ def text_input(*args, &block)
64
+ handle(Brush::TextInputTag.new, *args, &block)
65
+ end
66
+
67
+ def submit_button(*args, &block)
68
+ handle(Brush::SubmitButtonTag.new, *args, &block)
69
+ end
70
+
71
+ def page(*args, &block)
72
+ handle(Brush::Page.new, *args, &block)
73
+ end
74
+
75
+ def anchor(*args, &block)
76
+ handle(Brush::AnchorTag.new, *args, &block)
77
+ end
78
+
79
+ def space(n=1)
80
+ set_brush(Brush::GenericTextBrush.new("&nbsp;"*n))
81
+ end
82
+
83
+ def break
84
+ set_brush(Brush::GenericTagBrush.new("br"))
85
+ end
86
+
87
+ def image
88
+ set_brush(Brush::GenericTagBrush.new("img"))
89
+ end
90
+
91
+ def text(str)
92
+ set_brush(Brush::GenericTextBrush.new(str))
93
+ end
94
+ alias << text
95
+
96
+ def render(obj)
97
+ obj.render_on(self)
98
+ nil
99
+ end
100
+
101
+ private
102
+
103
+ def handle(brush, *args, &block)
104
+ set_brush(brush)
105
+ if not args.empty? or block
106
+ brush.with(*args, &block)
107
+ else
108
+ brush
109
+ end
110
+ end
111
+ end
112
+
113
+ class Brush
114
+ attr_accessor :parent, :canvas
115
+
116
+ def with(*args, &block)
117
+ raise "either args or block, but not both" if block and not args.empty?
118
+
119
+ @canvas.nest(&block) if block
120
+ @closed = true
121
+ end
122
+
123
+ def close
124
+ with unless @closed
125
+ end
126
+ end
127
+
128
+ class Brush::GenericTextBrush < Brush
129
+ def initialize(text)
130
+ @text = text
131
+ end
132
+
133
+ def with
134
+ doc = @canvas.document
135
+ doc << @text
136
+ super
137
+ nil
138
+ end
139
+ end
140
+
141
+ class Brush::GenericTagBrush < Brush
142
+ def initialize(tag)
143
+ @tag = tag
144
+ @attributes = Hash.new
145
+ end
146
+
147
+ def id(x)
148
+ @attributes["id"] = x
149
+ self
150
+ end
151
+
152
+ def method_missing(m, arg)
153
+ @attributes[m.to_s] = arg.to_s
154
+ self
155
+ end
156
+
157
+ def with(text=nil, &block)
158
+ doc = @canvas.document
159
+ doc.start_tag(@tag, @attributes)
160
+ if text
161
+ doc.text(text)
162
+ super(text, &block)
163
+ else
164
+ super(&block)
165
+ end
166
+ doc.end_tag(@tag)
167
+ nil
168
+ end
169
+ end
170
+
171
+ class Brush::TableTag < Brush::GenericTagBrush
172
+ def initialize
173
+ super('table')
174
+ end
175
+ end
176
+
177
+ class Brush::TableRowTag < Brush::GenericTagBrush
178
+ def initialize
179
+ super('tr')
180
+ end
181
+
182
+ def align_top
183
+ @attributes['align'] = 'top'
184
+ self
185
+ end
186
+
187
+ def columns(*cols)
188
+ with {
189
+ cols.each {|col| @canvas.table_data(col) }
190
+ }
191
+ end
192
+
193
+ def headings(*headers)
194
+ with {
195
+ headers.each {|head| @canvas.table_heading(head) }
196
+ }
197
+ end
198
+
199
+ def spanning_column(str, colspan)
200
+ with {
201
+ @canvas.table_data.col_span(colspan).with(str)
202
+ }
203
+ end
204
+
205
+ def spacer
206
+ with {
207
+ @canvas.table_data { @canvas.space }
208
+ }
209
+ end
210
+ end
211
+
212
+
213
+ class Brush::InputTag < Brush::GenericTagBrush
214
+ def initialize
215
+ super('input')
216
+ end
217
+
218
+ %w(type name value size maxlength checked src).each do |meth|
219
+ eval %[
220
+ def #{ meth }(arg)
221
+ @attributes['#{ meth }'] = arg
222
+ self
223
+ end
224
+ ]
225
+ end
226
+
227
+ def with
228
+ super
229
+ end
230
+ end
231
+
232
+ class Brush::TextInputTag < Brush::InputTag
233
+ def initialize
234
+ super
235
+ type('text')
236
+ end
237
+
238
+ def attr(attr_name)
239
+ assign(attr_name.to_s + "=")
240
+ value(@canvas.current_component.send(attr_name))
241
+ self
242
+ end
243
+
244
+ def assign(act, obj=nil)
245
+ ctx = @canvas.context.context
246
+ obj ||= @canvas.current_component
247
+
248
+ name(ctx.handler_registry.handler_id_for_input(obj, act))
249
+ end
250
+ end
251
+
252
+ class Brush::SubmitButtonTag < Brush::InputTag
253
+ def initialize
254
+ super
255
+ type('submit')
256
+ end
257
+
258
+ # TODO: action for another object
259
+ def action(act, *args)
260
+ ctx = @canvas.context.context
261
+ obj = @canvas.current_component
262
+
263
+ name(ctx.handler_registry.handler_id_for_action(Wee::ActionHandler[obj, act, *args]))
264
+ end
265
+ end
266
+
267
+ class Brush::TableDataTag < Brush::GenericTagBrush
268
+ def initialize
269
+ super('td')
270
+ end
271
+
272
+ def align_top
273
+ @attributes['align'] = 'top'
274
+ self
275
+ end
276
+ end
277
+
278
+ class Brush::TableHeaderTag < Brush::GenericTagBrush
279
+ def initialize
280
+ super('th')
281
+ end
282
+ end
283
+
284
+ module Brush::ActionMixin
285
+ # TODO: action for another object
286
+ def action(act, *args)
287
+ ctx = @canvas.context.context
288
+ obj = @canvas.current_component
289
+ href = ctx.application.gen_handler_url(ctx.session_id, ctx.page_id,
290
+ act ? ctx.handler_registry.handler_id_for_action(Wee::ActionHandler[obj, act, *args]) : '')
291
+ __action(href)
292
+ end
293
+ end
294
+
295
+ class Brush::FormTag < Brush::GenericTagBrush
296
+ include Brush::ActionMixin
297
+
298
+ def initialize
299
+ super('form')
300
+ @attributes['method'] = 'POST'
301
+ end
302
+
303
+ def __action(href)
304
+ @attributes['action'] = href
305
+ self
306
+ end
307
+
308
+ def with(*args, &block)
309
+ action(nil) unless @attributes.has_key?('action')
310
+ super
311
+ end
312
+ end
313
+
314
+ class Brush::AnchorTag < Brush::GenericTagBrush
315
+ include Brush::ActionMixin
316
+
317
+ def initialize
318
+ super('a')
319
+ end
320
+
321
+ def url(href)
322
+ @attributes['href'] = href
323
+ self
324
+ end
325
+
326
+ alias __action url
327
+ end
328
+
329
+
330
+ class Brush::Page < Brush
331
+ def title(str)
332
+ @title = str
333
+ self
334
+ end
335
+
336
+ def with(text=nil, &block)
337
+ doc = @canvas.document
338
+ doc.start_tag("html")
339
+
340
+ if @title
341
+ doc.start_tag("head")
342
+ doc.start_tag("title")
343
+ doc.text(@title)
344
+ doc.end_tag("title")
345
+ doc.end_tag("head")
346
+ end
347
+
348
+ doc.start_tag("body")
349
+
350
+ if text
351
+ doc.text(text)
352
+ super(text, &block)
353
+ else
354
+ super(&block)
355
+ end
356
+
357
+ doc.end_tag("body")
358
+ doc.end_tag("html")
359
+ nil
360
+ end
361
+ end
362
+
363
+ end # module Wee
364
+
365
+ if __FILE__ == $0
366
+ require 'html_writer'
367
+
368
+ doc = Wee::HtmlWriter.new('')
369
+ c = Wee::HtmlCanvas.new(nil, doc)
370
+ c.form.url("foo").with {
371
+ c.table {
372
+ c.table_row.id("myrow").with {
373
+ c.table_data.align_top.with("Hello world")
374
+ }
375
+ }
376
+ c.space
377
+ }
378
+ puts doc.port
379
+ end
@@ -0,0 +1,63 @@
1
+ class Wee::HtmlWriter
2
+ attr_accessor :port
3
+
4
+ def initialize(port)
5
+ @port = port
6
+ @open_start_tag = false
7
+ @tag_stack = []
8
+ end
9
+
10
+ def start_tag(tag, attributes={})
11
+ @port << ">" if @open_start_tag
12
+ @open_start_tag = true
13
+ @tag_stack.push(tag)
14
+
15
+ @port << "<#{ tag }"
16
+ attributes.each {|k, v| @port << %[ #{ k }="#{ v }"] }
17
+
18
+ self
19
+ end
20
+
21
+ def end_tag(tag)
22
+ raise "unbalanced html" if @tag_stack.pop != tag
23
+
24
+ if @open_start_tag
25
+ @port << "/>"
26
+ @open_start_tag = false
27
+ else
28
+ @port << "</#{ tag }>"
29
+ end
30
+
31
+ self
32
+ end
33
+
34
+ def text(str)
35
+ if @open_start_tag
36
+ @port << ">"
37
+ @open_start_tag = false
38
+ end
39
+ @port << str.to_s
40
+
41
+ self
42
+ end
43
+ alias << text
44
+
45
+ def valid?
46
+ @tag_stack.empty?
47
+ end
48
+
49
+ end
50
+
51
+ if __FILE__ == $0
52
+ doc = ''
53
+ w = Wee::HtmlWriter.new(doc)
54
+
55
+ w.start_tag('html')
56
+
57
+ w.start_tag('blah')
58
+ w.end_tag('blah')
59
+
60
+ w.end_tag('html')
61
+ p w.valid?
62
+ p doc
63
+ end