mullen-wee 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. data/README.rdoc +127 -0
  2. data/Rakefile +25 -0
  3. data/aWee.gemspec +26 -0
  4. data/examples/ObjectSpaceBrowser.rb +191 -0
  5. data/examples/ajax.rb +73 -0
  6. data/examples/apotomo-webhunter/main.rb +75 -0
  7. data/examples/apotomo-webhunter/public/images/bear_trap_charged.png +0 -0
  8. data/examples/apotomo-webhunter/public/images/bear_trap_snapped.png +0 -0
  9. data/examples/apotomo-webhunter/public/images/cheese.png +0 -0
  10. data/examples/apotomo-webhunter/public/images/dark_forest.jpg +0 -0
  11. data/examples/apotomo-webhunter/public/images/mouse.png +0 -0
  12. data/examples/apotomo-webhunter/public/javascripts/jquery-1.3.2.min.js +19 -0
  13. data/examples/apotomo-webhunter/public/javascripts/wee-jquery.js +19 -0
  14. data/examples/apotomo-webhunter/public/stylesheets/forest.css +33 -0
  15. data/examples/arc_challenge.rb +42 -0
  16. data/examples/arc_challenge2.rb +46 -0
  17. data/examples/cheese_task.rb +27 -0
  18. data/examples/continuations.rb +28 -0
  19. data/examples/demo.rb +135 -0
  20. data/examples/demo/calculator.rb +63 -0
  21. data/examples/demo/calendar.rb +333 -0
  22. data/examples/demo/counter.rb +38 -0
  23. data/examples/demo/editable_counter.rb +36 -0
  24. data/examples/demo/example.rb +142 -0
  25. data/examples/demo/file_upload.rb +19 -0
  26. data/examples/demo/messagebox.rb +15 -0
  27. data/examples/demo/radio.rb +33 -0
  28. data/examples/demo/window.rb +71 -0
  29. data/examples/hw.rb +11 -0
  30. data/examples/i18n/app.rb +16 -0
  31. data/examples/i18n/locale/de/app.po +25 -0
  32. data/examples/i18n/locale/en/app.po +25 -0
  33. data/examples/pager.rb +102 -0
  34. data/lib/wee.rb +109 -0
  35. data/lib/wee/application.rb +89 -0
  36. data/lib/wee/callback.rb +109 -0
  37. data/lib/wee/component.rb +363 -0
  38. data/lib/wee/decoration.rb +251 -0
  39. data/lib/wee/dialog.rb +171 -0
  40. data/lib/wee/external_resource.rb +39 -0
  41. data/lib/wee/html_brushes.rb +795 -0
  42. data/lib/wee/html_canvas.rb +254 -0
  43. data/lib/wee/html_document.rb +52 -0
  44. data/lib/wee/html_writer.rb +71 -0
  45. data/lib/wee/id_generator.rb +81 -0
  46. data/lib/wee/jquery.rb +11 -0
  47. data/lib/wee/jquery/jquery-1.3.2.min.js +19 -0
  48. data/lib/wee/jquery/wee-jquery.js +19 -0
  49. data/lib/wee/locale.rb +56 -0
  50. data/lib/wee/lru_cache.rb +91 -0
  51. data/lib/wee/presenter.rb +44 -0
  52. data/lib/wee/renderer.rb +72 -0
  53. data/lib/wee/request.rb +56 -0
  54. data/lib/wee/response.rb +68 -0
  55. data/lib/wee/rightjs.rb +11 -0
  56. data/lib/wee/rightjs/rightjs-1.5.2.min.js +9 -0
  57. data/lib/wee/rightjs/wee-rightjs.js +18 -0
  58. data/lib/wee/root_component.rb +45 -0
  59. data/lib/wee/session.rb +366 -0
  60. data/lib/wee/state.rb +102 -0
  61. data/lib/wee/task.rb +16 -0
  62. data/test/bm_render.rb +34 -0
  63. data/test/component_spec.rb +40 -0
  64. data/test/stress/plotter.rb +84 -0
  65. data/test/stress/stress_client.rb +51 -0
  66. data/test/stress/stress_local.rb +86 -0
  67. data/test/stress/stress_server.rb +83 -0
  68. data/test/test_component.rb +106 -0
  69. data/test/test_html_canvas.rb +25 -0
  70. data/test/test_html_writer.rb +32 -0
  71. data/test/test_lru_cache.rb +51 -0
  72. data/test/test_request.rb +42 -0
  73. metadata +185 -0
@@ -0,0 +1,254 @@
1
+ require 'wee/renderer'
2
+
3
+ module Wee
4
+
5
+ class HtmlCanvas < Renderer
6
+
7
+ def initialize(*args)
8
+ super
9
+ @current_brush = nil
10
+ end
11
+
12
+ def close
13
+ @current_brush.close if @current_brush
14
+ @current_brush = nil
15
+ end
16
+
17
+ def nest
18
+ old_brush = @current_brush
19
+ # we don't want that Brush#close is calledas #nest
20
+ # is called from #with -> this avoids an infinite loop
21
+ @current_brush = nil
22
+ yield
23
+ @current_brush.close if @current_brush
24
+ @current_brush = old_brush
25
+ end
26
+
27
+ def self.brush_tag(attr, klass, *args_to_new)
28
+ args_to_new = args_to_new.map {|a| a.inspect}.join(", ")
29
+ if klass.instance_method(:with).arity != 0
30
+ class_eval %{
31
+ def #{attr}(*args, &block)
32
+ handle(#{klass}.new(#{args_to_new}), *args, &block)
33
+ end
34
+ }
35
+ elsif klass.nesting?
36
+ class_eval %{
37
+ def #{attr}(&block)
38
+ handle2(#{klass}.new(#{args_to_new}), &block)
39
+ end
40
+ }
41
+ else
42
+ class_eval %{
43
+ def #{attr}
44
+ handle3(#{klass}.new(#{args_to_new}))
45
+ end
46
+ }
47
+ end
48
+ end
49
+
50
+ def self.generic_tag(*attrs)
51
+ attrs.each {|attr| brush_tag attr, Brush::GenericTagBrush, attr }
52
+ end
53
+
54
+ def self.generic_single_tag(*attrs)
55
+ attrs.each {|attr| brush_tag attr, Brush::GenericSingleTagBrush, attr }
56
+ end
57
+
58
+ generic_tag :html, :head, :body, :title, :label
59
+ generic_tag :h1, :h2, :h3, :h4, :h5
60
+ generic_tag :div, :span, :ul, :ol, :li, :pre
61
+ generic_single_tag :hr
62
+
63
+ brush_tag :link, Brush::LinkTag
64
+ brush_tag :table, Brush::TableTag
65
+ brush_tag :table_row, Brush::TableRowTag
66
+ brush_tag :table_data, Brush::TableDataTag
67
+ brush_tag :table_header, Brush::TableHeaderTag
68
+ brush_tag :form, Brush::FormTag
69
+ brush_tag :input, Brush::InputTag
70
+ brush_tag :hidden_input, Brush::HiddenInputTag
71
+ brush_tag :password_input, Brush::PasswordInputTag
72
+ brush_tag :text_input, Brush::TextInputTag
73
+ brush_tag :radio_button, Brush::RadioButtonTag
74
+ brush_tag :check_box, Brush::CheckboxTag; alias checkbox check_box
75
+ brush_tag :text_area, Brush::TextAreaTag
76
+ brush_tag :option, Brush::SelectOptionTag
77
+ brush_tag :submit_button, Brush::SubmitButtonTag
78
+ brush_tag :image_button, Brush::ImageButtonTag
79
+ brush_tag :file_upload, Brush::FileUploadTag
80
+ brush_tag :page, Brush::Page
81
+ brush_tag :anchor, Brush::AnchorTag
82
+ brush_tag :javascript, Brush::JavascriptTag
83
+ brush_tag :image, Brush::ImageTag
84
+ brush_tag :style, Brush::StyleTag
85
+
86
+ brush_tag :bold, Brush::GenericTagBrush, :b
87
+ brush_tag :paragraph, Brush::GenericTagBrush, :p
88
+ brush_tag :break, Brush::GenericSingleTagBrush, :br
89
+
90
+ def select_list(items, &block)
91
+ handle2(Brush::SelectListTag.new(items), &block)
92
+ end
93
+
94
+ HTML_NBSP = "&nbsp;".freeze
95
+
96
+ def space(n=1)
97
+ text(HTML_NBSP*n)
98
+ end
99
+
100
+ def text(str)
101
+ @current_brush.close if @current_brush
102
+ @current_brush = nil
103
+ @document.text(str)
104
+ nil
105
+ end
106
+
107
+ alias << text
108
+
109
+ def encode_text(str)
110
+ @current_brush.close if @current_brush
111
+ @current_brush = nil
112
+ @document.encode_text(str)
113
+ nil
114
+ end
115
+
116
+ def css(str)
117
+ style.type('text/css').with(str)
118
+ end
119
+
120
+ #
121
+ # Depends on an existing divert location :styles.
122
+ #
123
+ def render_style(component)
124
+ once(component.class) { try_divert(:styles, component.style) }
125
+ end
126
+
127
+ #
128
+ # converts \n into <br/>
129
+ #
130
+ def multiline_text(str, encode=true)
131
+ @current_brush.close if @current_brush
132
+ @current_brush = nil
133
+
134
+ first = true
135
+ str.each_line do |line|
136
+ @document.single_tag(:br) unless first
137
+ first = false
138
+
139
+ if encode
140
+ @document.encode_text(line)
141
+ else
142
+ @document.text(line)
143
+ end
144
+ end
145
+ end
146
+
147
+ #
148
+ # Define a divert location
149
+ #
150
+ def define_divert(tag)
151
+ @document.define_divert(tag)
152
+ end
153
+
154
+ #
155
+ # Change into an existing divert location and
156
+ # append +txt+ or the contents of +block+.
157
+ #
158
+ def divert(tag, txt=nil, &block)
159
+ @document.divert(tag, txt, &block)
160
+ end
161
+
162
+ #
163
+ # If the divert +tag+ exists, divert, otherwise
164
+ # do nothing.
165
+ #
166
+ def try_divert(tag, txt=nil, &block)
167
+ if @document.has_divert?(tag)
168
+ divert(tag, txt, &block)
169
+ true
170
+ else
171
+ false
172
+ end
173
+ end
174
+
175
+ #
176
+ # Render specific markup only once. For example style and/or
177
+ # javascript of a component which has many instances.
178
+ #
179
+ def once(tag)
180
+ return if @document.set.has_key?(tag)
181
+ @document.set[tag] = true
182
+ yield if block_given?
183
+ end
184
+
185
+ HTML_TYPE_CSS = 'text/css'.freeze
186
+ HTML_REL_STYLESHEET = 'stylesheet'.freeze
187
+
188
+ def link_css(url)
189
+ link.type(HTML_TYPE_CSS).rel(HTML_REL_STYLESHEET).href(url)
190
+ end
191
+
192
+ def new_radio_group
193
+ Wee::Brush::RadioButtonTag::RadioGroup.new(self)
194
+ end
195
+
196
+ def url_for_callback(callback, type=:action, hash=nil)
197
+ url_for_callback_id(register_callback(type, callback), hash)
198
+ end
199
+
200
+ def url_for_callback_id(callback_id, hash=nil)
201
+ if hash
202
+ build_url(hash.update(:callback_id => callback_id))
203
+ else
204
+ build_url(:callback_id => callback_id)
205
+ end
206
+ end
207
+
208
+ def build_url(*args)
209
+ @request.build_url(*args)
210
+ end
211
+
212
+ def register_callback(type, callback)
213
+ cbs = @callbacks
214
+ if cbs.respond_to?("#{type}_callbacks")
215
+ cbs.send("#{type}_callbacks").register(@current_component, callback)
216
+ else
217
+ raise
218
+ end
219
+ end
220
+
221
+ protected
222
+
223
+ def set_brush(brush)
224
+ brush.setup(self, @document)
225
+
226
+ @current_brush.close if @current_brush
227
+ @current_brush = brush
228
+
229
+ return brush
230
+ end
231
+
232
+ def handle(brush, *args, &block)
233
+ if block or not args.empty?
234
+ set_brush(brush)
235
+ brush.with(*args, &block)
236
+ else
237
+ set_brush(brush)
238
+ end
239
+ end
240
+
241
+ def handle2(brush, &block)
242
+ if block
243
+ set_brush(brush)
244
+ brush.with(&block)
245
+ else
246
+ set_brush(brush)
247
+ end
248
+ end
249
+
250
+ alias handle3 set_brush
251
+
252
+ end # class HtmlCanvas
253
+
254
+ end # module Wee
@@ -0,0 +1,52 @@
1
+ require 'wee/html_writer'
2
+
3
+ module Wee
4
+
5
+ #
6
+ # Represents a complete HTML document.
7
+ #
8
+ class HtmlDocument < HtmlWriter
9
+ def initialize
10
+ super([])
11
+ end
12
+
13
+ def set
14
+ @set ||= {}
15
+ end
16
+
17
+ def has_divert?(tag)
18
+ @divert and @divert[tag]
19
+ end
20
+
21
+ def define_divert(tag)
22
+ raise ArgumentError if has_divert?(tag)
23
+ @divert ||= {}
24
+ @port << (@divert[tag] = [])
25
+ end
26
+
27
+ def divert(tag, txt=nil, &block)
28
+ raise ArgumentError unless has_divert?(tag)
29
+ raise ArgumentError if txt and block
30
+
31
+ divert = @divert[tag]
32
+
33
+ if txt
34
+ divert << txt
35
+ end
36
+
37
+ if block
38
+ old_port = @port
39
+ begin
40
+ @port = divert
41
+ block.call
42
+ ensure
43
+ @port = old_port
44
+ end
45
+ end
46
+ end
47
+
48
+ def to_s
49
+ @port.join
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,71 @@
1
+ require 'rack'
2
+
3
+ module Wee
4
+
5
+ #
6
+ # A class used to write out HTML documents easily.
7
+ #
8
+ # Usage:
9
+ #
10
+ # w = Wee::HtmlWriter.new(doc='')
11
+ # w.start_tag('html')
12
+ # w.start_tag('body')
13
+ # w.start_tag('a', 'href' => 'http://...')
14
+ # w.text('link')
15
+ # w.end_tag('a')
16
+ # w.end_tag('body')
17
+ # w.end_tag('html')
18
+ #
19
+ # p doc # => '<html><body><a href="http://...">link</a></body></html>'
20
+ #
21
+ class HtmlWriter
22
+
23
+ attr_accessor :port
24
+
25
+ def initialize(port=[])
26
+ @port = port
27
+ end
28
+
29
+ CLOSING = ">".freeze
30
+ SINGLE_CLOSING = " />".freeze
31
+
32
+ def start_tag(tag, attributes=nil, single=false)
33
+ if attributes
34
+ @port << "<#{tag}"
35
+ attributes.each {|k, v|
36
+ if v
37
+ @port << %[ #{ k }="#{ v }"]
38
+ else
39
+ @port << %[ #{ k }]
40
+ end
41
+ }
42
+ @port << (single ? SINGLE_CLOSING : CLOSING)
43
+ else
44
+ @port << (single ? "<#{tag} />" : "<#{tag}>")
45
+ end
46
+ end
47
+
48
+ def single_tag(tag, attributes=nil)
49
+ start_tag(tag, attributes, true)
50
+ end
51
+
52
+ def end_tag(tag)
53
+ @port << "</#{tag}>"
54
+ end
55
+
56
+ def text(str)
57
+ @port << str.to_s
58
+ end
59
+
60
+ def encode_text(str)
61
+ @port << Rack::Utils.escape_html(str.to_s)
62
+ end
63
+
64
+ def write(str)
65
+ @port << str
66
+ end
67
+ alias << write
68
+
69
+ end # class HtmlWriter
70
+
71
+ end # module Wee
@@ -0,0 +1,81 @@
1
+ module Wee
2
+
3
+ #
4
+ # Abstract base class of all id generators.
5
+ #
6
+ class IdGenerator
7
+ def next
8
+ raise "subclass responsibility"
9
+ end
10
+ end
11
+
12
+ #
13
+ # Sequential id generator.
14
+ #
15
+ # Returned ids are guaranteed to be unique, but they are easily guessable.
16
+ #
17
+ class IdGenerator::Sequential < IdGenerator
18
+ def initialize(initial_value=0)
19
+ @value = initial_value - 1
20
+ end
21
+
22
+ def next
23
+ (@value += 1).to_s(36)
24
+ end
25
+ end
26
+
27
+ #
28
+ # Returned ids are unique with a very high probability and it's
29
+ # very hard to guess the next or any used id.
30
+ #
31
+ class IdGenerator::Secure < IdGenerator
32
+
33
+ require 'digest/md5'
34
+ begin
35
+ require 'securerandom'
36
+ rescue LoadError
37
+ end
38
+
39
+ def initialize(salt='wee')
40
+ @salt = salt
41
+
42
+ @use_secure = false
43
+ if defined?(::SecureRandom)
44
+ begin
45
+ @use_secure = true if next_secure != next_secure
46
+ rescue NotImplementedError
47
+ end
48
+ end
49
+ end
50
+
51
+ def next
52
+ pack(@use_secure ? next_secure : next_md5)
53
+ end
54
+
55
+ protected
56
+
57
+ def next_md5
58
+ now = Time.now
59
+ dig = Digest::MD5.new
60
+ dig.update(now.to_s)
61
+ dig.update(now.usec.to_s)
62
+ dig.update(rand(0).to_s)
63
+ dig.update($$.to_s)
64
+ dig.update(@salt.to_s)
65
+ dig.digest
66
+ end
67
+
68
+ def next_secure
69
+ SecureRandom.random_bytes(16)
70
+ end
71
+
72
+ def pack(str)
73
+ packed = [str].pack('m')
74
+ packed.tr!("=\r\n", '')
75
+ packed.tr!('+/', '-_')
76
+ packed
77
+ end
78
+
79
+ end
80
+
81
+ end # module Wee