aurita-gui 0.3.4 → 0.3.5

Sign up to get free protection for your applications and to get access to all the features.
data/TODO CHANGED
@@ -5,7 +5,6 @@
5
5
  - Fixme: Setting values only works after all elements have been added
6
6
  (values won't be set for elements added after form.values=)
7
7
 
8
- - Implement element.sibling[:dom_id] --> element
9
8
  - Implement XPath1.0 method (parent, sibling, descendant, following ...)
10
9
 
11
10
  - Implement field visibility using
@@ -20,6 +19,11 @@
20
19
 
21
20
  = DONE =============================================
22
21
 
22
+ - Element should implement / delegate to Array,
23
+ so it can be used like any container.
24
+
25
+ - Implement element.sibling[:dom_id] --> element
26
+
23
27
  - Provide markaby-like syntax, Example:
24
28
 
25
29
  HTML.div 'content here' :class => :highlight
@@ -27,7 +31,7 @@
27
31
  and
28
32
 
29
33
  HTML.build {
30
- div 'content' {
34
+ div.header {
31
35
  h1 'header'
32
36
  }
33
37
  }
@@ -14,7 +14,7 @@ as stand-alone library in any context (such as rails).
14
14
  As there seems to be a lack of ruby form generators, i decided to release this
15
15
  part of Aurita in a single gem with no dependencies.
16
16
  EOF
17
- s.version = '0.3.4'
17
+ s.version = '0.3.5'
18
18
  s.author = 'Tobias Fuchs'
19
19
  s.email = 'fuchs@atomnode.net'
20
20
  s.date = Time.now
@@ -25,6 +25,7 @@ part of Aurita in a single gem with no dependencies.
25
25
  'lib/aurita-gui/*',
26
26
  'lib/aurita-gui/form/*',
27
27
  'bin/*',
28
+ 'samples/*',
28
29
  'spec/*'].to_a
29
30
 
30
31
  s.has_rdoc = true
@@ -1,4 +1,6 @@
1
1
 
2
+ require('delegate')
3
+
2
4
  module Aurita
3
5
  module GUI
4
6
 
@@ -14,11 +16,46 @@ module GUI
14
16
  # via parameter :content or using a
15
17
  # block or by #content and #content=.
16
18
  #
19
+ # == Usage as container
20
+ #
21
+ # Element implements all features expected from a
22
+ # container class.
23
+ # It delegates access to @content to class Array,
24
+ # so an element can be used as Array instance, too:
25
+ #
26
+ # e = Element.new { Element.new { 'first' } + Element.new { 'second' } }
27
+ # puts e.join(' -- ')
28
+ # -->
29
+ # 'first -- second'
30
+ #
31
+ # You can also push elements into an element:
32
+ #
33
+ # e1 = HTML.div { 'Foo' }
34
+ # e2 = HTML.div { 'Bar' }
35
+ #
36
+ # assert_equal(e[0], 'Foo')
37
+ # assert_equal(e[1], e2)
38
+ #
39
+ # It also keeps track of parent classes:
40
+ #
41
+ # assert_equal(e1[1].parent, e1)
42
+ #
43
+ # Random access operators are redefined, so you
44
+ # can either access elements by array index, as usual,
45
+ # as well as by their DOM id:
46
+ #
47
+ # e = Element.new { Element.new(:tag => :p, :id => :foo) { 'nested element' } }
48
+ # puts e[:foo].to_s
49
+ # -->
50
+ # '<p id="foo">nested element</p>'
51
+ #
52
+ # == Builder
53
+ #
17
54
  # Most methods invoked on an Element instance are
18
55
  # redirected to return or set a tag attribute.
19
56
  # Example:
20
57
  #
21
- # link = Element(:tag => :a) { 'klick me' }
58
+ # link = Element.new(:tag => :a) { 'click me' }
22
59
  # link.href = '/link/to/somewhere'
23
60
  #
24
61
  # Same as
@@ -108,11 +145,11 @@ module GUI
108
145
  # e.onclick == 'alert("message");'
109
146
  # e.to_s == '<div onclick="alert(\"message\");"></div>'
110
147
  #
111
- class Element
148
+ class Element < DelegateClass(Array)
112
149
 
113
150
  @@element_count = 0
114
151
 
115
- attr_accessor :attrib, :content, :parent, :force_closing_tag, :tag
152
+ attr_accessor :attrib, :parent, :force_closing_tag, :tag
116
153
 
117
154
  def initialize(*args, &block)
118
155
 
@@ -144,52 +181,73 @@ module GUI
144
181
  end
145
182
  @content = [ @content ] unless (@content.kind_of? Array or @content.to_s.length == 0)
146
183
  @content ||= []
184
+
185
+ @content.each { |c|
186
+ if c.is_a?(Element) then
187
+ c.parent = self
188
+ end
189
+ }
147
190
  params.delete(:content)
148
191
  params.delete(:tag)
149
- # params[:id] = self.class.to_s.split('::')[-1].downcase + '_' << @@element_count.to_s if params[:id].nil?
150
- # params[:onclick] << ';' unless params[:onclick].nil? or params[:onclick].include?(';')
151
192
 
152
193
  @attrib = params
153
- # @attrib[:id] = @attrib[:id].to_s
154
-
194
+
195
+ super(@content)
196
+
155
197
  end
156
198
 
157
199
  def has_content?
158
- (@content.length > 0)
200
+ (length > 0)
159
201
  end
160
202
 
161
- # Return DOM id of this element.
162
- def dom_id
163
- @attrib[:id] if @attrib
164
- end
165
- # Set DOM id of this element.
166
- def dom_id=(value)
167
- @attrib[:id] = value if @attrib
168
- end
169
203
  # Alias definition for #dom_id=(value)
170
204
  # Define explicitly so built-in method #id
171
205
  # is not invoked instead
172
206
  def id=(value)
173
- @attrib[:id] = value
207
+ @attrib[:id] = value if @attrib
174
208
  end
209
+ alias dom_id= id=
175
210
  # Alias definition for #dom_id()
176
211
  def id
177
- @attrib[:id]
212
+ @attrib[:id] if @attrib
178
213
  end
214
+ alias dom_id id
179
215
 
180
- # Render this element to a string and append another
181
- # element.
216
+ # Return [ self, other ] so concatenation of
217
+ # Element instances works as expected;
218
+ #
219
+ # HTML.build {
220
+ # div { 'first' } + div { 'second' }
221
+ # }
222
+ # --> <Element [ <Element 'first'>, <Element 'second'> ] >
223
+ #
182
224
  def +(other)
183
- # return string << other.string if other.kind_of? Element
184
225
  return [ self, other ]
185
226
  end
186
- alias << +
187
227
 
228
+ # Append object to array of nested elements.
229
+ # Object to append (other) does not have to
230
+ # be an Element instance.
231
+ # If so, however, other#parent will be set
232
+ # to this instance.
233
+ def <<(other)
234
+ other.parent = self if other.is_a?(Element)
235
+ __getobj__().push(other)
236
+ end
237
+
238
+ # Returns [ self ], so concatenation with
239
+ # Arrays and other Element instances works
240
+ # as expected (see #<<(other).
188
241
  def to_ary
189
242
  [ self ]
190
243
  end
191
244
  alias to_a to_ary
192
245
 
246
+ # Returns nested content as array.
247
+ def get_content
248
+ __getobj__()
249
+ end
250
+
193
251
  # Redirect methods to setting or retreiving tag
194
252
  # attributes.
195
253
  # There are several possible routings for method_missing:
@@ -220,16 +278,20 @@ module GUI
220
278
  if block_given? then
221
279
  @attrib[:class] = meth
222
280
  @attrib.update(value) if value.is_a? Hash
223
- @content = yield
281
+ c = yield
282
+ c = [ c ] unless c.is_a?(Array)
283
+ __setobj__(c)
224
284
  return self
225
285
  elsif !value.nil? && !meth.to_s.include?('=') then
226
286
  @attrib[:class] = meth
227
287
  case value
228
288
  when Hash then
229
289
  @attrib.update(value)
230
- @content = value[:content]
290
+ c = value[:content]
291
+ c = [ c ] if (c && !c.is_a?(Array))
292
+ __setobj__(c) if c
231
293
  when String then
232
- @content = value
294
+ __setobj__([value])
233
295
  end
234
296
  return self
235
297
  else
@@ -240,9 +302,11 @@ module GUI
240
302
 
241
303
  # Set enclosed content of this element.
242
304
  # Will be automatically wrapped in an array.
243
- def content=(obj)
244
- @content = [ obj ]
305
+ def set_content(obj)
306
+ return __setobj__([ obj ]) unless (obj.is_a?(Array))
307
+ __setobj__(obj)
245
308
  end
309
+ alias content= set_content
246
310
 
247
311
  # Define explicitly so built-in method #type
248
312
  # is not invoked instead
@@ -252,7 +316,7 @@ module GUI
252
316
 
253
317
  # Do not redirect random access operators.
254
318
  def [](index)
255
- return @content[index] if (index.is_a? Numeric)
319
+ return super(index) if (index.is_a?(Fixnum))
256
320
  return find_by_dom_id(index)
257
321
  end
258
322
 
@@ -260,7 +324,7 @@ module GUI
260
324
  # its dom_id
261
325
  def find_by_dom_id(dom_id)
262
326
  dom_id = dom_id.to_sym
263
- @content.each { |c|
327
+ each { |c|
264
328
  if c.is_a? Element then
265
329
  return c if (c.dom_id == dom_id)
266
330
  sub = c.find_by_dom_id(dom_id)
@@ -272,16 +336,10 @@ module GUI
272
336
 
273
337
  # Do not redirect random access operators.
274
338
  def []=(index,element)
275
- @content[index] = element if (index.is_a? Numeric)
339
+ super(index,element) if (index.is_a? Numeric)
276
340
  e = find_by_dom_id(index)
277
341
  e.swap(element)
278
342
  end
279
- def length
280
- @content.length
281
- end
282
- def empty?
283
- @content.length == 0
284
- end
285
343
 
286
344
  # Copy constructor. Replace self with
287
345
  # other element.
@@ -290,7 +348,7 @@ module GUI
290
348
  @tag = other.tag
291
349
  @attrib = other.attrib
292
350
  @attrib[:id] = save_own_id
293
- @content = other.content
351
+ __setobj__(other.get_content)
294
352
  end
295
353
  alias copy swap
296
354
 
@@ -302,43 +360,37 @@ module GUI
302
360
 
303
361
  # Render this element to a string.
304
362
  def string
305
- return content.to_s if @tag == :pseudo
363
+ return get_content.to_s if @tag == :pseudo
306
364
 
307
365
  attrib_string = ''
308
366
  @attrib.each_pair { |name,value|
309
367
  if value.instance_of?(Array) then
310
368
  value = value.join(' ')
311
- elsif
312
- value.instance_of?(TrueClass) then
369
+ elsif value.instance_of?(TrueClass) then
313
370
  value = name
314
371
  end
315
372
  if !value.nil? then
316
- value = value.to_s
317
- attrib_string << ' ' << name.to_s + '="' << value.gsub('"','\"') + '"'
373
+ value = value.to_s.gsub('"','\"')
374
+ attrib_string << " #{name}=\"#{value}\""
318
375
  end
319
376
  }
320
377
 
321
- out = ''
322
378
  if (!(@force_closing_tag.instance_of?(FalseClass)) &&
323
379
  [ :div, :label, :button, :textarea ].include?(@tag)) then
324
380
  @force_closing_tag = true
325
381
  end
326
- if @force_closing_tag || content.to_s != '' then
327
- out << "<#{@tag}"
328
- out << attrib_string if attrib_string.length > 0
329
- out << ">#{content}"
330
- out << "</#{@tag}>"
382
+ if @force_closing_tag || has_content? then
383
+ return "<#{@tag}#{attrib_string}>#{__getobj__}</#{@tag}>"
331
384
  else
332
- out = "<#{@tag.to_s}#{attrib_string} />"
385
+ return "<#{@tag.to_s}#{attrib_string} />"
333
386
  end
334
- return out
335
387
  end
336
388
  alias to_s string
389
+ alias to_str string
337
390
 
338
- def each(&block)
339
- @content.each(&block)
340
- end
341
-
391
+ # Return CSS classes as array. Note that
392
+ # Element#class is not redefined to return
393
+ # attribute :class, for obvious reasons.
342
394
  def css_classes
343
395
  css_classes = @attrib[:class]
344
396
  if css_classes.kind_of? Array
@@ -348,21 +400,76 @@ module GUI
348
400
  else # e.g. Symbol
349
401
  css_classes = [ css_classes ]
350
402
  end
351
- css_classes.collect { |c| c.to_sym if c }
403
+ css_classes.map! { |c| c.to_sym if c }
352
404
  return css_classes
353
405
  end
354
406
  alias css_class css_classes
355
407
 
408
+ # Add CSS class to this Element instance.
409
+ # e = Element.new(:class => :first)
410
+ # e.add_class(:second
411
+ # e.to_s
412
+ # -->
413
+ # <div class="first second"></div>
356
414
  def add_class(css_class_name)
357
415
  @attrib[:class] = (css_classes << css_class_name.to_sym)
358
416
  end
417
+ alias add_css_class add_class
359
418
 
419
+ # Remove CSS class from this Element instance.
420
+ # Add CSS class to this Element instance.
421
+ # e = Element.new(:class => [ :first, :second ])
422
+ # e.to_s
423
+ # -->
424
+ # <div class="first second"></div>
425
+ #
426
+ # e.remove_class(:second)
427
+ # e.to_s
428
+ # -->
429
+ # <div class="first"></div>
360
430
  def remove_class(css_class_name)
361
431
  classes = css_classes
362
432
  classes.delete(css_class_name.to_sym)
363
433
  @attrib[:class] = classes
364
434
  end
365
-
435
+ alias remove_css_class remove_class
436
+
437
+ # Iterates over all Elements in this
438
+ # instances object tree (depth first).
439
+ #
440
+ # x = HTML.build {
441
+ # div.main {
442
+ # h2.header { 'Title' } +
443
+ # div.lead { 'Intro here' } +
444
+ # div.body {
445
+ # p.section { 'First' } +
446
+ # p.section { 'Second' }
447
+ # }
448
+ # }
449
+ # }
450
+ #
451
+ # x.recurse { |element|
452
+ # p element.css_class
453
+ # }
454
+ #
455
+ # -->
456
+ #
457
+ # :main
458
+ # :header
459
+ # :lead
460
+ # :body
461
+ # :section
462
+ # :section
463
+ #
464
+ def recurse(&block)
465
+ each { |c|
466
+ if c.is_a?(Element) then
467
+ yield(c)
468
+ c.recurse(&block)
469
+ end
470
+ }
471
+ end
472
+
366
473
  end # class
367
474
 
368
475
  end # module
@@ -3,6 +3,7 @@ require('aurita-gui/form/form_field')
3
3
 
4
4
  module Aurita
5
5
  module GUI
6
+ # TODO: Use ArrayFields for option field/value storage
6
7
 
7
8
  # Abstract base class for all form elements containing
8
9
  # options, like Select_Field, Radio_Field, Checkbox_Field
@@ -4,6 +4,9 @@ require('aurita-gui/element')
4
4
  module Aurita
5
5
  module GUI
6
6
 
7
+ # = Aurita::GUI
8
+ # Tobias Fuchs, 2009
9
+ #
7
10
  # == About
8
11
  #
9
12
  # Aurita::GUI is a library for convenient, simple
File without changes
@@ -0,0 +1,17 @@
1
+
2
+ require 'rubygems'
3
+ require 'aurita-gui'
4
+
5
+ include Aurita::GUI
6
+
7
+ e1 = HTML.div.outer { 'Foo' }
8
+ e2 = HTML.div.inner { 'Bar' }
9
+
10
+ e1 << e2
11
+
12
+ puts e1.to_s
13
+ p e1[0] == 'Foo'
14
+ p e1[1] == e2
15
+
16
+ p e1[1].parent == e1
17
+ p e2.parent == e1
@@ -0,0 +1,22 @@
1
+
2
+ require 'rubygems'
3
+ require 'aurita-gui'
4
+
5
+ include Aurita::GUI
6
+
7
+
8
+ class Renderfoo
9
+
10
+ def outerfun(i)
11
+ i * i
12
+ end
13
+
14
+ def render
15
+ puts HTML.build {
16
+ outerfun(23)
17
+ }.to_s
18
+ end
19
+
20
+ end
21
+
22
+ Renderfoo.new.render
@@ -0,0 +1,21 @@
1
+
2
+ require 'rubygems'
3
+ require 'aurita-gui'
4
+
5
+ include Aurita::GUI
6
+
7
+ x = HTML.build {
8
+ div.main {
9
+ h2.header { 'Title' } +
10
+ div.lead { 'Intro here' } +
11
+ div.body {
12
+ p.section { 'First' } +
13
+ p.section { 'Second' } +
14
+ p.section { 'Third' }
15
+ }
16
+ }
17
+ }
18
+
19
+ x.recurse { |element|
20
+ p element.css_class
21
+ }
File without changes
@@ -41,8 +41,9 @@ describe Aurita::GUI::Element, "basic rendering" do
41
41
  e1 = Element.new(:id => :first)
42
42
  e2 = Element.new(:id => :second)
43
43
 
44
- (e1 << e2).should == [ e1, e2 ]
45
44
  (e1 + e2).should == [ e1, e2 ]
45
+ e1 << e2
46
+ e1[0].should == e2
46
47
  end
47
48
 
48
49
  it "should be able to render to string" do
@@ -51,14 +52,14 @@ describe Aurita::GUI::Element, "basic rendering" do
51
52
  end
52
53
 
53
54
  it "should have enclosed content that is an array" do
54
- @e1.content.length.should == 0
55
+ @e1.get_content.length.should == 0
55
56
  @e1.has_content?().should == false
56
- @e1.content.should == []
57
+ @e1.get_content.should == []
57
58
  end
58
59
 
59
60
  it "should close the tag depending on content" do
60
61
  @e1.content = 'the content'
61
- @e1.content.should == [ 'the content' ]
62
+ @e1.get_content.should == [ 'the content' ]
62
63
  @e1.to_s.should == '<tagname>the content</tagname>'
63
64
  end
64
65
 
@@ -97,7 +98,7 @@ describe Aurita::GUI::Element, "basic rendering" do
97
98
 
98
99
  it "should accept parameter :content" do
99
100
  e = Element.new(:tag => :bar, :content => 'content here', :name => :wombat)
100
- e.content.should == ['content here']
101
+ e.get_content.should == ['content here']
101
102
  e.name.should == :wombat
102
103
  e.to_s.should == '<bar name="wombat">content here</bar>'
103
104
  end
@@ -105,7 +106,7 @@ describe Aurita::GUI::Element, "basic rendering" do
105
106
  it "should accept content as block, maintaining object identity" do
106
107
  test_obj_identity = 'lorem_ipsum'
107
108
  e = Element.new(:tag => :jada) { test_obj_identity }
108
- e.content.should == [ test_obj_identity ]
109
+ e.get_content.should == [ test_obj_identity ]
109
110
  e.tag.should == :jada
110
111
  end
111
112
 
@@ -117,18 +118,18 @@ describe Aurita::GUI::Element, "basic rendering" do
117
118
  end
118
119
 
119
120
  it "should accept other element instances as content" do
120
- @outer.content.should == [ @inner ]
121
+ @outer.get_content.should == [ @inner ]
121
122
  @outer.to_s.should == '<p class="outer"><h2>i am an inner header</h2></p>'
122
123
  end
123
124
 
124
125
  it "should maintain an object hierarchy" do
125
- @outer.content.first.new_attrib = 23
126
- @outer.content.first.new_attrib.should == 23
126
+ @outer.get_content.first.new_attrib = 23
127
+ @outer.get_content.first.new_attrib.should == 23
127
128
  end
128
129
 
129
130
  it "should be possible to alter an enclosed element after adding it as content" do
130
131
  @inner.decorated_attrib = 'decorated'
131
- @inner.content << ' with decoration'
132
+ @inner.get_content << ' with decoration'
132
133
 
133
134
  @outer.to_s.should == '<p class="outer"><h2 decorated_attrib="decorated">i am an inner header with decoration</h2></p>'
134
135
 
@@ -157,10 +158,10 @@ describe Aurita::GUI::Element, "basic rendering" do
157
158
  dwa = 'two'
158
159
  tri = 'three'
159
160
  e.content = ras
160
- e.content.should == [ ras ]
161
- e.content << dwa
162
- e.content << tri
163
- e.content.should == [ ras, dwa, tri ]
161
+ e.get_content.should == [ ras ]
162
+ e << dwa
163
+ e << tri
164
+ e.get_content.should == [ ras, dwa, tri ]
164
165
  end
165
166
 
166
167
  end
@@ -38,15 +38,15 @@ describe Aurita::GUI::HTML, "basic rendering" do
38
38
  @e[0].css_class.first.should == :outer
39
39
  @e[0][0].id.should == :header
40
40
  @e[0][1].id.should == :content
41
- @e[0][1].content.should == [ 'Content' ]
41
+ @e[0][1].get_content.should == [ 'Content' ]
42
42
  @e[0][1].content = 'Altered'
43
- @e[0][1].content.should == [ 'Altered' ]
43
+ @e[0][1].get_content.should == [ 'Altered' ]
44
44
  @e.to_s.should == '<div class="outer"><h2 id="header">Header</h2><p id="content">Altered</p></div>'
45
45
  end
46
46
 
47
47
  it "should be possible to retreive elements just by DOM id" do
48
48
  e = @e[:header]
49
- e.content.first.should == 'Header'
49
+ e.get_content.first.should == 'Header'
50
50
  end
51
51
 
52
52
  it "should escape double-quotes in tag parameters" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aurita-gui
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.4
4
+ version: 0.3.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tobias Fuchs
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-01-26 00:00:00 +01:00
12
+ date: 2009-01-27 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -22,15 +22,14 @@ extensions: []
22
22
  extra_rdoc_files: []
23
23
 
24
24
  files:
25
- - cheatsheet.rb
26
25
  - spec
27
26
  - History.txt
28
27
  - lib
28
+ - samples
29
29
  - aurita-gui.gemspec
30
30
  - bin
31
31
  - TODO
32
32
  - test
33
- - valuetest.rb
34
33
  - LICENSE
35
34
  - lib/aurita-gui
36
35
  - lib/aurita-gui.rb
@@ -59,6 +58,11 @@ files:
59
58
  - lib/aurita-gui/form/template_helper.rb
60
59
  - lib/aurita-gui/form/input_field.rb
61
60
  - lib/aurita-gui/form/date_field.rb
61
+ - samples/putstest.rb
62
+ - samples/recurse.rb
63
+ - samples/cheatsheet.rb
64
+ - samples/valuetest.rb
65
+ - samples/pushtest.rb
62
66
  - spec/marshal.rb
63
67
  - spec/javascript.rb
64
68
  - spec/form.rb