sws 0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (158) hide show
  1. data/doc/DOC.otl +34 -0
  2. data/doc/Makefile +13 -0
  3. data/doc/architecture.dia +0 -0
  4. data/doc/docbook/architecture.png +0 -0
  5. data/doc/docbook/concepts.docbook +474 -0
  6. data/doc/docbook/installation.docbook +57 -0
  7. data/doc/docbook/introduction.docbook +130 -0
  8. data/doc/docbook/sws_manual.docbook +35 -0
  9. data/doc/docbook/todo.docbook +38 -0
  10. data/doc/docbook/tutorial.docbook +594 -0
  11. data/examples/README +1 -0
  12. data/examples/addressbook/CardBrowse/CardBrowse.html +43 -0
  13. data/examples/addressbook/CardBrowse/CardBrowse.rb +65 -0
  14. data/examples/addressbook/CardBrowse/CardBrowse.sws +92 -0
  15. data/examples/addressbook/Login/LoginPage.html +12 -0
  16. data/examples/addressbook/Login/LoginPage.rb +19 -0
  17. data/examples/addressbook/Login/LoginPage.sws +15 -0
  18. data/examples/addressbook/README +1 -0
  19. data/examples/addressbook/addressbook.rb +70 -0
  20. data/examples/addressbook/application.yaml +8 -0
  21. data/examples/addressbook/db.yaml +7 -0
  22. data/examples/component_demo/CheckBoxDemo/CheckBoxDemo.html +11 -0
  23. data/examples/component_demo/CheckBoxDemo/CheckBoxDemo.rb +21 -0
  24. data/examples/component_demo/CheckBoxDemo/CheckBoxDemo.sws +25 -0
  25. data/examples/component_demo/ComponentDemo.rb +21 -0
  26. data/examples/component_demo/ConditionalDemo/ConditionalDemo.html +18 -0
  27. data/examples/component_demo/ConditionalDemo/ConditionalDemo.rb +2 -0
  28. data/examples/component_demo/ConditionalDemo/ConditionalDemo.sws +22 -0
  29. data/examples/component_demo/FileUploadDemo/FileUploadDemo.html +10 -0
  30. data/examples/component_demo/FileUploadDemo/FileUploadDemo.rb +9 -0
  31. data/examples/component_demo/FileUploadDemo/FileUploadDemo.sws +33 -0
  32. data/examples/component_demo/FormFieldsDemo/FormFieldsDemo.html +12 -0
  33. data/examples/component_demo/FormFieldsDemo/FormFieldsDemo.rb +21 -0
  34. data/examples/component_demo/FormFieldsDemo/FormFieldsDemo.sws +40 -0
  35. data/examples/component_demo/FormListsDemo/FormListsDemo.html +11 -0
  36. data/examples/component_demo/FormListsDemo/FormListsDemo.rb +37 -0
  37. data/examples/component_demo/FormListsDemo/FormListsDemo.sws +47 -0
  38. data/examples/component_demo/GenericDemo/GenericDemo.html +4 -0
  39. data/examples/component_demo/GenericDemo/GenericDemo.rb +2 -0
  40. data/examples/component_demo/GenericDemo/GenericDemo.sws +10 -0
  41. data/examples/component_demo/HyperlinkDemo/HyperlinkDemo.html +8 -0
  42. data/examples/component_demo/HyperlinkDemo/HyperlinkDemo.rb +20 -0
  43. data/examples/component_demo/HyperlinkDemo/HyperlinkDemo.sws +19 -0
  44. data/examples/component_demo/ImageLinkDemo/ImageLinkDemo.html +11 -0
  45. data/examples/component_demo/ImageLinkDemo/ImageLinkDemo.rb +2 -0
  46. data/examples/component_demo/ImageLinkDemo/ImageLinkDemo.sws +14 -0
  47. data/examples/component_demo/PageWrapper/PageWrapper.html +23 -0
  48. data/examples/component_demo/PageWrapper/PageWrapper.rb +2 -0
  49. data/examples/component_demo/PageWrapper/PageWrapper.sws +42 -0
  50. data/examples/component_demo/README +1 -0
  51. data/examples/component_demo/RepetitionDemo/RepetitionDemo.html +13 -0
  52. data/examples/component_demo/RepetitionDemo/RepetitionDemo.rb +19 -0
  53. data/examples/component_demo/RepetitionDemo/RepetitionDemo.sws +20 -0
  54. data/examples/component_demo/StringDemo/StringDemo.html +5 -0
  55. data/examples/component_demo/StringDemo/StringDemo.rb +16 -0
  56. data/examples/component_demo/StringDemo/StringDemo.sws +14 -0
  57. data/examples/component_demo/application.yaml +28 -0
  58. data/examples/component_demo/poweredby.jpg +0 -0
  59. data/examples/component_demo/style.css +1 -0
  60. data/examples/movies/Menu/Menu.html +3 -0
  61. data/examples/movies/Menu/Menu.rb +7 -0
  62. data/examples/movies/Menu/Menu.sws +7 -0
  63. data/examples/movies/MovieBrowse/MovieBrowse.html +68 -0
  64. data/examples/movies/MovieBrowse/MovieBrowse.rb +178 -0
  65. data/examples/movies/MovieBrowse/MovieBrowse.sws +127 -0
  66. data/examples/movies/README +1 -0
  67. data/examples/movies/UserBrowse/UserBrowse.html +50 -0
  68. data/examples/movies/UserBrowse/UserBrowse.rb +69 -0
  69. data/examples/movies/UserBrowse/UserBrowse.sws +49 -0
  70. data/examples/movies/application.yaml +11 -0
  71. data/examples/movies/da.rb +36 -0
  72. data/examples/movies/dbmovies.rb +44 -0
  73. data/examples/movies/frameworks/TestFramework/framework.yaml +4 -0
  74. data/examples/movies/frameworks/TestFramework/resources/im1.jpg +0 -0
  75. data/examples/movies/images/pbr1b.jpg +0 -0
  76. data/examples/movies/movies.rb +28 -0
  77. data/examples/movies/movies.sds +119 -0
  78. data/examples/movies/movies.sqlite +0 -0
  79. data/examples/movies/movies_mysql.sql +28 -0
  80. data/examples/movies/movies_postgres.sql +27 -0
  81. data/examples/movies/movies_sqlite.sql +28 -0
  82. data/lib/sws.rb +89 -0
  83. data/lib/sws/Core/components/CheckBox/CheckBox.api +5 -0
  84. data/lib/sws/Core/components/CheckBox/CheckBox.rb +45 -0
  85. data/lib/sws/Core/components/CheckBoxList/CheckBoxList.api +13 -0
  86. data/lib/sws/Core/components/CheckBoxList/CheckBoxList.rb +54 -0
  87. data/lib/sws/Core/components/Conditional/Conditional.api +3 -0
  88. data/lib/sws/Core/components/Conditional/Conditional.html +1 -0
  89. data/lib/sws/Core/components/Conditional/Conditional.rb +39 -0
  90. data/lib/sws/Core/components/Conditional/Conditional.sws +2 -0
  91. data/lib/sws/Core/components/Content/Content.rb +18 -0
  92. data/lib/sws/Core/components/ExceptionPage/ExceptionPage.html +13 -0
  93. data/lib/sws/Core/components/ExceptionPage/ExceptionPage.rb +18 -0
  94. data/lib/sws/Core/components/ExceptionPage/ExceptionPage.sws +16 -0
  95. data/lib/sws/Core/components/FileUpload/FileUpload.api +16 -0
  96. data/lib/sws/Core/components/FileUpload/FileUpload.rb +62 -0
  97. data/lib/sws/Core/components/Form/Form.api +9 -0
  98. data/lib/sws/Core/components/Form/Form.html +3 -0
  99. data/lib/sws/Core/components/Form/Form.rb +55 -0
  100. data/lib/sws/Core/components/Form/Form.sws +12 -0
  101. data/lib/sws/Core/components/GenericContainer/GenericContainer.api +10 -0
  102. data/lib/sws/Core/components/GenericContainer/GenericContainer.html +1 -0
  103. data/lib/sws/Core/components/GenericContainer/GenericContainer.rb +39 -0
  104. data/lib/sws/Core/components/GenericContainer/GenericContainer.sws +12 -0
  105. data/lib/sws/Core/components/GenericElement/GenericElement.api +10 -0
  106. data/lib/sws/Core/components/GenericElement/GenericElement.rb +34 -0
  107. data/lib/sws/Core/components/HiddenField/HiddenField.api +7 -0
  108. data/lib/sws/Core/components/HiddenField/HiddenField.rb +37 -0
  109. data/lib/sws/Core/components/Hyperlink/Hyperlink.api +13 -0
  110. data/lib/sws/Core/components/Hyperlink/Hyperlink.html +1 -0
  111. data/lib/sws/Core/components/Hyperlink/Hyperlink.rb +102 -0
  112. data/lib/sws/Core/components/Hyperlink/Hyperlink.sws +12 -0
  113. data/lib/sws/Core/components/Image/Image.api +11 -0
  114. data/lib/sws/Core/components/Image/Image.rb +49 -0
  115. data/lib/sws/Core/components/ImageButton/ImageButton.api +16 -0
  116. data/lib/sws/Core/components/ImageButton/ImageButton.rb +76 -0
  117. data/lib/sws/Core/components/Link/Link.api +11 -0
  118. data/lib/sws/Core/components/Link/Link.rb +39 -0
  119. data/lib/sws/Core/components/PasswordField/PasswordField.api +7 -0
  120. data/lib/sws/Core/components/PasswordField/PasswordField.rb +41 -0
  121. data/lib/sws/Core/components/RadioButton/RadioButton.api +7 -0
  122. data/lib/sws/Core/components/RadioButton/RadioButton.rb +44 -0
  123. data/lib/sws/Core/components/RadioButtonList/RadioButtonList.api +20 -0
  124. data/lib/sws/Core/components/RadioButtonList/RadioButtonList.rb +76 -0
  125. data/lib/sws/Core/components/Repetition/Repetition.api +10 -0
  126. data/lib/sws/Core/components/Repetition/Repetition.html +1 -0
  127. data/lib/sws/Core/components/Repetition/Repetition.rb +137 -0
  128. data/lib/sws/Core/components/Repetition/Repetition.sws +2 -0
  129. data/lib/sws/Core/components/ResetButton/ResetButton.api +5 -0
  130. data/lib/sws/Core/components/ResetButton/ResetButton.rb +28 -0
  131. data/lib/sws/Core/components/Select/Select.api +24 -0
  132. data/lib/sws/Core/components/Select/Select.rb +57 -0
  133. data/lib/sws/Core/components/String/String.api +5 -0
  134. data/lib/sws/Core/components/String/String.rb +28 -0
  135. data/lib/sws/Core/components/SubmitButton/SubmitButton.api +6 -0
  136. data/lib/sws/Core/components/SubmitButton/SubmitButton.rb +53 -0
  137. data/lib/sws/Core/components/TextArea/TextArea.api +9 -0
  138. data/lib/sws/Core/components/TextArea/TextArea.rb +28 -0
  139. data/lib/sws/Core/components/TextField/TextField.api +9 -0
  140. data/lib/sws/Core/components/TextField/TextField.rb +46 -0
  141. data/lib/sws/Core/framework.yaml +25 -0
  142. data/lib/sws/JSComponents/components/JSMenu/JSMenu.api +5 -0
  143. data/lib/sws/JSComponents/components/JSMenu/JSMenu.html +58 -0
  144. data/lib/sws/JSComponents/components/JSMenu/JSMenu.rb +34 -0
  145. data/lib/sws/JSComponents/components/JSMenu/JSMenu.sws +37 -0
  146. data/lib/sws/JSComponents/framework.yaml +3 -0
  147. data/lib/sws/adaptor.rb +334 -0
  148. data/lib/sws/application.rb +604 -0
  149. data/lib/sws/component.rb +656 -0
  150. data/lib/sws/cookie.rb +27 -0
  151. data/lib/sws/direct_action.rb +38 -0
  152. data/lib/sws/extensions.rb +49 -0
  153. data/lib/sws/parsers.rb +374 -0
  154. data/lib/sws/request.rb +308 -0
  155. data/lib/sws/response.rb +70 -0
  156. data/lib/sws/session.rb +195 -0
  157. data/lib/sws/slot.rb +198 -0
  158. metadata +263 -0
@@ -0,0 +1,27 @@
1
+ module SWS
2
+
3
+
4
+ # Represents HTML cookie
5
+ class Cookie
6
+
7
+
8
+ attr_reader :key
9
+ attr_reader :value
10
+ attr_reader :path
11
+
12
+ #TODO: add domain?
13
+
14
+ # Creates new Cookie with given key=value pair and optionally path
15
+ def initialize ( key, value, path="/" )
16
+ @key,@value,@path = key,value,path
17
+ end
18
+
19
+
20
+ # Returns cookie representation in HTTP header form
21
+ def to_s
22
+ return "Set-Cookie: #{@key}=#{@value}; path=#{@path}"
23
+ end
24
+
25
+ end
26
+
27
+ end
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ module SWS
4
+
5
+ # DirectAction is a way to define multiple entry point to the application.
6
+ # Default entry point is a default_component defined in application config
7
+ # file. But sometimes you may need more entry points. In such a situation
8
+ # create appropiate ..._action methods in your DirectAction class and then you
9
+ # may access them by using
10
+ # http://application_url/direct_action_key/method_name_without_action_word
11
+ # URL.
12
+ # DirectAction requests are served by instances of this class by default. You
13
+ # can also define your own classes for this purpose.
14
+ class DirectAction
15
+
16
+ # The Request object the receiver is associated to
17
+ attr_reader :request
18
+
19
+ def initialize ( request )
20
+ @request = request
21
+ end
22
+
23
+ # This methods returns default_component instance
24
+ def default_action ()
25
+
26
+ component = Component.create( Application.instance.default_component_class_name, nil, @request )
27
+ return component.process_request( @request )
28
+
29
+ end
30
+
31
+ def action_for_name ( name )
32
+ # TODO: handle non-existing action?
33
+ return method( name + "_action" ).call()
34
+ end
35
+
36
+ end
37
+
38
+ end
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Extensions to String class - encoding and decoding of URL-encoded string
4
+ class String
5
+
6
+
7
+ # Decode URL-encoded string - returns decoded string.
8
+ def url_decode ()
9
+ tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n) do
10
+ [$1.delete('%')].pack('H*')
11
+ end
12
+
13
+ end
14
+
15
+
16
+ # Decode URL-encoded string - modifies the receiver. Returns decoded string.
17
+ def url_decode! ()
18
+
19
+ tr!('+', ' ')
20
+ gsub!(/((?:%[0-9a-fA-F]{2})+)/n) do
21
+ [$1.delete('%')].pack('H*')
22
+ end
23
+ return self
24
+
25
+ end
26
+
27
+
28
+ # Encode string with URL-encoding - returns encoded string.
29
+ def url_encode ()
30
+
31
+ gsub(/([^ a-zA-Z0-9_.-]+)/n) do
32
+ '%' + $1.unpack('H2' * $1.size).join('%').upcase
33
+ end.tr(' ', '+')
34
+
35
+ end
36
+
37
+
38
+ # Encode string with URL-encoding - modifies the receiver. Returns encoded
39
+ # string.
40
+ def url_encode! ()
41
+
42
+ gsub!(/([^ a-zA-Z0-9_.-]+)/n) do
43
+ '%' + $1.unpack('H2' * $1.size).join('%').upcase
44
+ end.tr(' ', '+')
45
+
46
+ end
47
+
48
+ end
49
+
@@ -0,0 +1,374 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Definition and template parser and helper classes
4
+ module SWS
5
+
6
+ # Class that retrieves definition of the component from .sws and/or .api files.
7
+ # Parsed definitions are cached to avoid unnecessary overhead.
8
+ class DefinitionParser
9
+
10
+ include Singleton
11
+
12
+ def initialize ()
13
+
14
+ # .sws file cache
15
+ @sws_cache = Hash.new do |hash,filename|
16
+ $log_sws_parser.debug( "Parsing .sws #{filename}" )
17
+ hash[filename] = YAML::load( File.open( filename ) ) #sws_parse( filename )
18
+ end
19
+
20
+ # .api file cache
21
+ @api_cache = Hash.new do |hash,filename|
22
+ $log_sws_parser.debug( "Parsing .api #{filename}" )
23
+ hash[filename] = YAML::load( File.open( filename ) )
24
+ end
25
+
26
+ end
27
+
28
+
29
+ # Most important method of the class - returns Component object for given
30
+ # token in given parent component. Does it by parsing parent definition file
31
+ # and looking for definition of Component with given token name. When the
32
+ # definition is found, new Component object with proper slots and definition
33
+ # (again retrieved from file and parsed) is created.
34
+ def component_for_token_with_parent ( token, parent )
35
+
36
+
37
+ # Element to find - component definition
38
+ component_definition = nil
39
+
40
+ # Definition is looked for in parent component recursively - up to the
41
+ # topmost component
42
+ next_parent = parent
43
+
44
+ name = token.sws_name
45
+
46
+ loop do
47
+
48
+ $log_sws_parser.debug( "Looking for #{name} in #{next_parent}" )
49
+
50
+ # Because this is the parent (so it has children) we don't have to check
51
+ # if the .sws file is present
52
+ parent_definition = @sws_cache[ next_parent.definition_filename ]
53
+
54
+ # Definition of component looked for in parent definition - if not
55
+ # found, the parent's parent will be searched
56
+ # FIXME: this will surely work incorrectly when 2 nested components have
57
+ # subcomponents of the same name!
58
+ component_definition = parent_definition[name]
59
+
60
+ if ( component_definition != nil )
61
+ break
62
+ elsif ( next_parent.parent != nil )
63
+ next_parent = next_parent.parent
64
+ else
65
+ raise( "Definiton for component #{name} not found!" )
66
+ end
67
+
68
+ end
69
+
70
+ $log_sws_parser.debug( "Definition found" )
71
+
72
+ # Create Component object using component_definition hash
73
+ class_name = component_definition[ "_class" ]
74
+ unless( class_name )
75
+ raise( "Cannot find _class attribute for component #{token.sws_name}" )
76
+ end
77
+ component = Component.create( class_name, parent.request, name.dup(), parent )
78
+ component.definition_component = next_parent
79
+ component.html_attrs = token.attributes
80
+
81
+ slots = Hash.new
82
+
83
+ if ( component.api_filename != nil )
84
+ @api_cache[ component.api_filename ].each_pair do |slot_name, slot_attrs|
85
+
86
+ slot = Slot.new( component, slot_name )
87
+ slot.bind( component_definition[slot_name] )
88
+
89
+ if ( slot_attrs )
90
+ slot.default = slot_attrs["default"]
91
+ slot.required = slot_attrs["required"]
92
+ slot.settable = slot_attrs["settable"]
93
+ end
94
+
95
+ slots[slot_name] = slot
96
+ end
97
+ end
98
+
99
+ component.slots = slots
100
+ component.synchronize_slots()
101
+ return component
102
+
103
+ end
104
+
105
+ end
106
+
107
+
108
+ # Parser for HTML templates of the components.
109
+ class TemplateParser
110
+
111
+ @@file_data = {}
112
+
113
+ # Creates new TemplateParser for given filename.
114
+ def initialize ( filename )
115
+
116
+ $log_sws_parser.debug( "Creating template parser for name #{filename}" )
117
+ @template_filename = filename
118
+
119
+ end
120
+
121
+
122
+ # Main parsing method - parses definition file into the tree of
123
+ # TemplateToken objects
124
+ def parse ()
125
+
126
+ begin
127
+ #TODO: implement debug mode which forces sws to reload
128
+ # template file every time parse() is called
129
+ unless( @@file_data[ @template_filename ] )
130
+ @@file_data[ @template_filename ] = File.read( @template_filename )
131
+ end
132
+ template_data = @@file_data[ @template_filename ]
133
+
134
+ rescue Exception
135
+ raise "Cannot read template data from file \"#{@template_filename}\""
136
+ end
137
+
138
+ tokenized_data = template_data.scan( /<!--.*?-->|<[^<>]+>|[^<>]+/ )
139
+ root_token = create_token_tree( tokenized_data )
140
+
141
+ return root_token
142
+
143
+ end
144
+
145
+
146
+ private
147
+
148
+ # Parses attributes of the tag - used only for SWS tags, so returns null if "sws"
149
+ # attribute is not found
150
+ def parse_attributes ( tag )
151
+
152
+ attrs = Hash.new
153
+
154
+ # Scans tag attrs - matches also attrs with no value, like "selected"
155
+ # parameter of checkbox or "disabled"
156
+ tag.scan( /\s+(\w+)\s*=?\s*(['"])(.*?)\2|\s+(\w+)\s*=?\s*([^'"\s>]*)/ ).each do |name,quote,value,second_name,second_value|
157
+ unless ( name )
158
+ name = second_name
159
+ value = second_value
160
+ end
161
+ value ||= quote
162
+ attrs[name.downcase] = value
163
+ end
164
+
165
+ return attrs["sws"] ? attrs : nil
166
+
167
+ end
168
+
169
+
170
+ # Creates token tree from the array of lexems
171
+ def create_token_tree ( lexems )
172
+
173
+ nesting_level = 0
174
+ root_tokens = Array.new
175
+ current_token = nil
176
+
177
+ lexems.reverse.each do |lexem|
178
+
179
+ if ( comment?( lexem ) )
180
+
181
+ token = TemplateToken.new( current_token,nil,true,true )
182
+ token.data = lexem
183
+ if ( current_token )
184
+ current_token.children << token
185
+ else
186
+ root_tokens << token
187
+ end
188
+
189
+ elsif ( closing?( lexem ) )
190
+
191
+ tag_name = lexem.scan( /^<\/(\w+)>$/ )[0][0].downcase
192
+ token = TemplateToken.new( current_token,tag_name )
193
+ if ( current_token )
194
+ current_token.children << token
195
+ else
196
+ root_tokens << token
197
+ end
198
+ current_token = token
199
+ nesting_level += 1
200
+
201
+ elsif ( opening_or_standalone?( lexem ) )
202
+
203
+ tag_name = lexem.scan( /^<(\w+)/ )[0][0].downcase
204
+ if ( current_token && current_token.name == tag_name ) # tag should be closed
205
+ attrs = parse_attributes( lexem )
206
+ if ( attrs )
207
+ current_token.attributes = attrs
208
+ else
209
+ # Why should we parse an ordinal tag (attributes etc) and then
210
+ # generate it again, if we can just put the original lexem?
211
+ current_token.data = lexem
212
+ end
213
+ current_token = current_token.parent
214
+ nesting_level -= 1
215
+ else # standalone tag
216
+ token = TemplateToken.new( current_token,tag_name,true )
217
+ attrs = parse_attributes( lexem )
218
+ if ( attrs )
219
+ token.attributes = attrs
220
+ else
221
+ token.data = lexem
222
+ end
223
+ if ( current_token )
224
+ current_token.children << token
225
+ else
226
+ root_tokens << token
227
+ end
228
+ end
229
+
230
+ else #text token
231
+
232
+ token = TemplateToken.new( current_token,nil,true )
233
+ token.data = lexem
234
+ if ( current_token )
235
+ current_token.children << token
236
+ else
237
+ root_tokens << token
238
+ end
239
+
240
+ end
241
+
242
+ end
243
+
244
+ root_tokens.each { |token| token.reverse() }
245
+ root_tokens.reverse!
246
+
247
+ unless ( nesting_level == 0 )
248
+ raise( "Invalid .html template file - probably some tags are not closed" )
249
+ end
250
+ #root_tokens.each { |token| token.dump ( "" ) }
251
+
252
+ return root_tokens
253
+
254
+ end
255
+
256
+
257
+ # Returns true if the tag is an opening or standalone tag
258
+ def opening_or_standalone? ( tag )
259
+ return ( tag =~ /^<\w+/ )
260
+ end
261
+
262
+
263
+ # Returns true if the tag is a HTML comment
264
+ def comment? ( tag )
265
+ return tag =~ /^<!--.*-->$/
266
+ end
267
+
268
+
269
+ # Returns true if the tag is a closing tag
270
+ def closing? (tag)
271
+ return ( tag =~ /^<\/\w+>/ )
272
+ end
273
+
274
+ end
275
+
276
+
277
+ # Internal class - used only by TemplateParser. Represents a HTML tag or text
278
+ # token
279
+ class TemplateToken
280
+
281
+ attr_reader :parent, :name, :children
282
+ attr_accessor :attributes, :data
283
+
284
+
285
+ # Creates new Token with given parent
286
+ def initialize ( parent,name,standalone=false,comment=false )
287
+
288
+ @parent = parent
289
+ @name = name
290
+ @children = Array.new
291
+ @comment = comment
292
+ @standalone = standalone
293
+ @data = nil
294
+
295
+ end
296
+
297
+ # Reverses receiver's children array. Used at the end of parsing process, as
298
+ # parsing is performed backwards (otherwise it is hard to distinguish
299
+ # open/close and standalone tags)
300
+ def reverse ()
301
+ @children.reverse!
302
+ @children.each { |child| child.reverse() }
303
+ end
304
+
305
+ # Returns true if the receiver represents a Component
306
+ def sws? ()
307
+ return @name != nil && @attributes != nil
308
+ end
309
+
310
+ # Returns name of the Component
311
+ def sws_name ()
312
+ return @attributes["sws"]
313
+ end
314
+
315
+
316
+ # Returns true if the receiver represents a HTML tag
317
+ def tag? ()
318
+ return @name != nil && @data != nil
319
+ end
320
+
321
+
322
+ # Returns true if the receiver is a purely text one
323
+ def text? ()
324
+ return @name == nil
325
+ end
326
+
327
+
328
+ # Returns true if the receiver is a HTML comment
329
+ def comment? ()
330
+ return @comment
331
+ end
332
+
333
+
334
+ # Returns true if the receiver is a standalone tag
335
+ def standalone? ()
336
+ return @standalone
337
+ end
338
+
339
+
340
+ # Returns string representation of the receiver
341
+ def to_s ()
342
+
343
+ if( comment? )
344
+ return "comment"
345
+ elsif ( text? )
346
+ return "text"
347
+ elsif( tag? )
348
+ return "#{data}"
349
+ else
350
+ attrs = @attributes.to_a.join( "| " )
351
+ return "#{@name} #{attrs}"
352
+ end
353
+
354
+ end
355
+
356
+ # Dumps the token recursively in a tree form.
357
+ def dump ( prefix )
358
+ if( comment? )
359
+ puts "#{prefix}comment"
360
+ elsif ( text? )
361
+ puts "#{prefix}text"
362
+ elsif( tag? )
363
+ puts "#{prefix}#{data}"
364
+ @children.each { |child| child.dump( prefix + " " ) }
365
+ else
366
+ attrs = @attributes.to_a.join( "| " )
367
+ puts "#{prefix}#{@name} #{attrs}"
368
+ @children.each { |child| child.dump( prefix + " " ) }
369
+ end
370
+ end
371
+
372
+ end
373
+
374
+ end