hobo 0.5.3

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.
Files changed (125) hide show
  1. data/LICENSE.txt +22 -0
  2. data/README.txt +18 -0
  3. data/bin/hobo +81 -0
  4. data/hobo_files/plugin/CHANGES.txt +963 -0
  5. data/hobo_files/plugin/LICENSE.txt +22 -0
  6. data/hobo_files/plugin/README +4 -0
  7. data/hobo_files/plugin/Rakefile +11 -0
  8. data/hobo_files/plugin/generators/hobo/hobo_generator.rb +37 -0
  9. data/hobo_files/plugin/generators/hobo/templates/application.dryml +2 -0
  10. data/hobo_files/plugin/generators/hobo/templates/guest.rb +31 -0
  11. data/hobo_files/plugin/generators/hobo_front_controller/USAGE +11 -0
  12. data/hobo_files/plugin/generators/hobo_front_controller/hobo_front_controller_generator.rb +90 -0
  13. data/hobo_files/plugin/generators/hobo_front_controller/templates/controller.rb +51 -0
  14. data/hobo_files/plugin/generators/hobo_front_controller/templates/functional_test.rb +18 -0
  15. data/hobo_files/plugin/generators/hobo_front_controller/templates/helper.rb +2 -0
  16. data/hobo_files/plugin/generators/hobo_front_controller/templates/index.dryml +43 -0
  17. data/hobo_files/plugin/generators/hobo_front_controller/templates/login.dryml +44 -0
  18. data/hobo_files/plugin/generators/hobo_front_controller/templates/search.dryml +18 -0
  19. data/hobo_files/plugin/generators/hobo_front_controller/templates/signup.dryml +45 -0
  20. data/hobo_files/plugin/generators/hobo_model/USAGE +26 -0
  21. data/hobo_files/plugin/generators/hobo_model/hobo_model_generator.rb +38 -0
  22. data/hobo_files/plugin/generators/hobo_model/templates/fixtures.yml +11 -0
  23. data/hobo_files/plugin/generators/hobo_model/templates/migration.rb +13 -0
  24. data/hobo_files/plugin/generators/hobo_model/templates/model.rb +24 -0
  25. data/hobo_files/plugin/generators/hobo_model/templates/unit_test.rb +10 -0
  26. data/hobo_files/plugin/generators/hobo_model_controller/USAGE +30 -0
  27. data/hobo_files/plugin/generators/hobo_model_controller/hobo_model_controller_generator.rb +43 -0
  28. data/hobo_files/plugin/generators/hobo_model_controller/templates/controller.rb +5 -0
  29. data/hobo_files/plugin/generators/hobo_model_controller/templates/functional_test.rb +18 -0
  30. data/hobo_files/plugin/generators/hobo_model_controller/templates/helper.rb +2 -0
  31. data/hobo_files/plugin/generators/hobo_model_controller/templates/view.rhtml +2 -0
  32. data/hobo_files/plugin/generators/hobo_rapid/hobo_rapid_generator.rb +51 -0
  33. data/hobo_files/plugin/generators/hobo_rapid/templates/hobo_rapid.js +436 -0
  34. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/default_mapping.rb +11 -0
  35. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/banner.gif +0 -0
  36. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg_bodytop.gif +0 -0
  37. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg_corner_01.gif +0 -0
  38. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg_corner_02.gif +0 -0
  39. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg_corner_03.gif +0 -0
  40. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg_corner_04.gif +0 -0
  41. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg_shadow_bottom.gif +0 -0
  42. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg_shadow_left.gif +0 -0
  43. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg_shadow_right.gif +0 -0
  44. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg_shadow_top.gif +0 -0
  45. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/header_blue.gif +0 -0
  46. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/header_dblue.gif +0 -0
  47. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/header_green.gif +0 -0
  48. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/header_purple.gif +0 -0
  49. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/header_red.gif +0 -0
  50. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/logo.gif +0 -0
  51. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/spinner.gif +0 -0
  52. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/txt_list_img_dblue.gif +0 -0
  53. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/txt_list_img_green.gif +0 -0
  54. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/txt_list_img_purple.gif +0 -0
  55. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/txt_list_img_red.gif +0 -0
  56. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window_corner_01.gif +0 -0
  57. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window_corner_02.gif +0 -0
  58. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window_corner_03.gif +0 -0
  59. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window_corner_04.gif +0 -0
  60. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window_shadow_bottom.gif +0 -0
  61. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window_shadow_left.gif +0 -0
  62. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window_shadow_right.gif +0 -0
  63. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window_shadow_top.gif +0 -0
  64. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/stylesheets/application.css +390 -0
  65. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/views/application.dryml +104 -0
  66. data/hobo_files/plugin/generators/hobo_user_model/USAGE +26 -0
  67. data/hobo_files/plugin/generators/hobo_user_model/hobo_user_model_generator.rb +38 -0
  68. data/hobo_files/plugin/generators/hobo_user_model/templates/fixtures.yml +11 -0
  69. data/hobo_files/plugin/generators/hobo_user_model/templates/migration.rb +15 -0
  70. data/hobo_files/plugin/generators/hobo_user_model/templates/model.rb +58 -0
  71. data/hobo_files/plugin/generators/hobo_user_model/templates/unit_test.rb +10 -0
  72. data/hobo_files/plugin/init.rb +44 -0
  73. data/hobo_files/plugin/lib/action_view_extensions/base.rb +14 -0
  74. data/hobo_files/plugin/lib/active_record/has_many_association.rb +54 -0
  75. data/hobo_files/plugin/lib/active_record/has_many_through_association.rb +22 -0
  76. data/hobo_files/plugin/lib/active_record/table_definition.rb +34 -0
  77. data/hobo_files/plugin/lib/extensions.rb +245 -0
  78. data/hobo_files/plugin/lib/extensions/test_case.rb +130 -0
  79. data/hobo_files/plugin/lib/hobo.rb +353 -0
  80. data/hobo_files/plugin/lib/hobo/HtmlString +3 -0
  81. data/hobo_files/plugin/lib/hobo/authenticated_user.rb +106 -0
  82. data/hobo_files/plugin/lib/hobo/authentication_support.rb +108 -0
  83. data/hobo_files/plugin/lib/hobo/composite_model.rb +66 -0
  84. data/hobo_files/plugin/lib/hobo/controller.rb +134 -0
  85. data/hobo_files/plugin/lib/hobo/controller_helpers.rb +135 -0
  86. data/hobo_files/plugin/lib/hobo/core.rb +475 -0
  87. data/hobo_files/plugin/lib/hobo/define_tags.rb +56 -0
  88. data/hobo_files/plugin/lib/hobo/dryml.rb +161 -0
  89. data/hobo_files/plugin/lib/hobo/dryml/dryml_builder.rb +126 -0
  90. data/hobo_files/plugin/lib/hobo/dryml/tag_module.rb +9 -0
  91. data/hobo_files/plugin/lib/hobo/dryml/taglib.rb +57 -0
  92. data/hobo_files/plugin/lib/hobo/dryml/template.rb +586 -0
  93. data/hobo_files/plugin/lib/hobo/dryml/template_environment.rb +302 -0
  94. data/hobo_files/plugin/lib/hobo/dryml/template_handler.rb +19 -0
  95. data/hobo_files/plugin/lib/hobo/generator.rb +25 -0
  96. data/hobo_files/plugin/lib/hobo/html_string.rb +3 -0
  97. data/hobo_files/plugin/lib/hobo/lazy_hash.rb +28 -0
  98. data/hobo_files/plugin/lib/hobo/mapping_tags.rb +262 -0
  99. data/hobo_files/plugin/lib/hobo/markdown_string.rb +7 -0
  100. data/hobo_files/plugin/lib/hobo/model.rb +391 -0
  101. data/hobo_files/plugin/lib/hobo/model_controller.rb +676 -0
  102. data/hobo_files/plugin/lib/hobo/model_queries.rb +92 -0
  103. data/hobo_files/plugin/lib/hobo/model_support.rb +44 -0
  104. data/hobo_files/plugin/lib/hobo/password_string.rb +3 -0
  105. data/hobo_files/plugin/lib/hobo/predicate_dispatch.rb +78 -0
  106. data/hobo_files/plugin/lib/hobo/proc_binding.rb +32 -0
  107. data/hobo_files/plugin/lib/hobo/rapid.rb +447 -0
  108. data/hobo_files/plugin/lib/hobo/static_tags +92 -0
  109. data/hobo_files/plugin/lib/hobo/text.rb +3 -0
  110. data/hobo_files/plugin/lib/hobo/textile_string.rb +13 -0
  111. data/hobo_files/plugin/lib/hobo/undefined.rb +41 -0
  112. data/hobo_files/plugin/lib/hobo/undefined_access_error.rb +5 -0
  113. data/hobo_files/plugin/lib/hobo/where_fragment.rb +23 -0
  114. data/hobo_files/plugin/lib/rexml.rb +345 -0
  115. data/hobo_files/plugin/tags/core.dryml +6 -0
  116. data/hobo_files/plugin/tags/rapid.dryml +177 -0
  117. data/hobo_files/plugin/tags/rapid_editing.dryml +168 -0
  118. data/hobo_files/plugin/tags/rapid_navigation.dryml +95 -0
  119. data/hobo_files/plugin/tags/rapid_pages.dryml +175 -0
  120. data/hobo_files/plugin/tasks/environments.rake +19 -0
  121. data/hobo_files/plugin/tasks/hobo_tasks.rake +4 -0
  122. data/hobo_files/plugin/test/hobo_dryml_template_test.rb +7 -0
  123. data/hobo_files/plugin/test/hobo_test.rb +7 -0
  124. data/hobo_files/plugin/uninstall.rb +1 -0
  125. metadata +206 -0
@@ -0,0 +1,92 @@
1
+ a
2
+ abbr
3
+ acronym
4
+ address
5
+ applet
6
+ area
7
+ b
8
+ base
9
+ basefont
10
+ bdo
11
+ big
12
+ blockquote
13
+ body
14
+ br
15
+ button
16
+ caption
17
+ center
18
+ cite
19
+ code
20
+ col
21
+ colgroup
22
+ dd
23
+ del
24
+ dfn
25
+ dir
26
+ div
27
+ dl
28
+ dt
29
+ em
30
+ embed
31
+ fieldset
32
+ font
33
+ form
34
+ frame
35
+ frameset
36
+ h1
37
+ h2
38
+ h3
39
+ h4
40
+ h5
41
+ h6
42
+ head
43
+ hr
44
+ html
45
+ i
46
+ iframe
47
+ img
48
+ input
49
+ ins
50
+ isindex
51
+ kbd
52
+ label
53
+ legend
54
+ li
55
+ link
56
+ map
57
+ menu
58
+ meta
59
+ noframes
60
+ noscript
61
+ object
62
+ ol
63
+ optgroup
64
+ option
65
+ p
66
+ param
67
+ pre
68
+ q
69
+ s
70
+ samp
71
+ script
72
+ select
73
+ small
74
+ span
75
+ strike
76
+ strong
77
+ style
78
+ sub
79
+ sup
80
+ table
81
+ tbody
82
+ td
83
+ textarea
84
+ tfoot
85
+ th
86
+ thead
87
+ title
88
+ tr
89
+ tt
90
+ u
91
+ ul
92
+ var
@@ -0,0 +1,3 @@
1
+ class Hobo::Text < String
2
+
3
+ end
@@ -0,0 +1,13 @@
1
+ class Hobo::TextileString < String
2
+
3
+ def to_html
4
+ if text.blank?
5
+ ""
6
+ else
7
+ textilized = RedCloth.new(self, [ :hard_breaks ])
8
+ textilized.hard_breaks = true if textilized.respond_to?("hard_breaks=")
9
+ textilized.to_html
10
+ end
11
+ end
12
+
13
+ end
@@ -0,0 +1,41 @@
1
+ module Hobo
2
+
3
+ class Undefined
4
+
5
+ def initialize(klass=Object)
6
+ @klass = klass
7
+ end
8
+
9
+ def hobo_undefined?
10
+ true
11
+ end
12
+
13
+ def class
14
+ @klass
15
+ end
16
+
17
+ def is_a?(klass)
18
+ return klass == @klass || klass > @klass
19
+ end
20
+
21
+ def to_s
22
+ "<Hobo::Undefined #{@klass}>"
23
+ end
24
+
25
+ def inspect
26
+ to_s
27
+ end
28
+
29
+ def new_record?
30
+ true
31
+ end
32
+
33
+ def method_missing(name, *args)
34
+ raise UndefinedAccessError.new("call to: #{name}")
35
+ end
36
+
37
+ undef_method :==
38
+
39
+ end
40
+
41
+ end
@@ -0,0 +1,5 @@
1
+ module Hobo
2
+
3
+ class UndefinedAccessError < RuntimeError; end
4
+
5
+ end
@@ -0,0 +1,23 @@
1
+ module Hobo
2
+
3
+ class WhereFragment
4
+
5
+ def initialize(sql, *params)
6
+ @sql = params.empty? ? sql : ActiveRecord::Base.send(:sanitize_sql, [sql] + params)
7
+ end
8
+
9
+ def &(rhs)
10
+ WhereFragment.new("(#{to_sql}) and (#{rhs.to_sql})")
11
+ end
12
+
13
+ def |(rhs)
14
+ WhereFragment.new("(#{to_sql}) or (#{rhs.to_sql})")
15
+ end
16
+
17
+ def to_sql
18
+ @sql
19
+ end
20
+
21
+ end
22
+
23
+ end
@@ -0,0 +1,345 @@
1
+ # Hobo needs to process XML as transparently as possibe. In the case of tags
2
+ # that are not defined by hobo (i.e. html tags), they should pass through just
3
+ # as they were in the dryml source. Recontructing the tags from the DOM is not
4
+ # good enough. The extensions to REXML in here allow Hobo to use the original
5
+ # start tag source in the output.
6
+ # There's also some fixes/extras to allow error messages with line numbers.
7
+
8
+ # The main hack is that Element nodes have two instance variables added:
9
+ # @start_tag_source and @source_offset
10
+
11
+ # So cool that Ruby allows us to redfine a method. Such a shame the method
12
+ # happened to be 200 lines long :-(
13
+
14
+ require 'rexml/document'
15
+
16
+ module REXML
17
+ module Parsers
18
+ class BaseParser
19
+ def pull
20
+ if @closed
21
+ x, @closed = @closed, nil
22
+ return [ :end_element, x ]
23
+ end
24
+ return [ :end_document ] if empty?
25
+ return @stack.shift if @stack.size > 0
26
+ @source.read if @source.buffer.size<2
27
+ if @document_status == nil
28
+ @source.consume( /^\s*/um )
29
+ word = @source.match( /(<[^>]*)>/um )
30
+ word = word[1] unless word.nil?
31
+ case word
32
+ when COMMENT_START
33
+ return [ :comment, @source.match( COMMENT_PATTERN, true )[1] ]
34
+ when XMLDECL_START
35
+ results = @source.match( XMLDECL_PATTERN, true )[1]
36
+ version = VERSION.match( results )
37
+ version = version[1] unless version.nil?
38
+ encoding = ENCODING.match(results)
39
+ encoding = encoding[1] unless encoding.nil?
40
+ @source.encoding = encoding
41
+ standalone = STANDALONE.match(results)
42
+ standalone = standalone[1] unless standalone.nil?
43
+ return [ :xmldecl, version, encoding, standalone]
44
+ when INSTRUCTION_START
45
+ return [ :processing_instruction, *@source.match(INSTRUCTION_PATTERN, true)[1,2] ]
46
+ when DOCTYPE_START
47
+ md = @source.match( DOCTYPE_PATTERN, true )
48
+ identity = md[1]
49
+ close = md[2]
50
+ identity =~ IDENTITY
51
+ name = $1
52
+ raise REXML::ParseException("DOCTYPE is missing a name") if name.nil?
53
+ pub_sys = $2.nil? ? nil : $2.strip
54
+ long_name = $3.nil? ? nil : $3.strip
55
+ uri = $4.nil? ? nil : $4.strip
56
+ args = [ :start_doctype, name, pub_sys, long_name, uri ]
57
+ if close == ">"
58
+ @document_status = :after_doctype
59
+ @source.read if @source.buffer.size<2
60
+ md = @source.match(/^\s*/um, true)
61
+ @stack << [ :end_doctype ]
62
+ else
63
+ @document_status = :in_doctype
64
+ end
65
+ return args
66
+ else
67
+ @document_status = :after_doctype
68
+ @source.read if @source.buffer.size<2
69
+ md = @source.match(/\s*/um, true)
70
+ end
71
+ end
72
+ if @document_status == :in_doctype
73
+ md = @source.match(/\s*(.*?>)/um)
74
+ case md[1]
75
+ when SYSTEMENTITY
76
+ match = @source.match( SYSTEMENTITY, true )[1]
77
+ return [ :externalentity, match ]
78
+
79
+ when ELEMENTDECL_START
80
+ return [ :elementdecl, @source.match( ELEMENTDECL_PATTERN, true )[1] ]
81
+
82
+ when ENTITY_START
83
+ match = @source.match( ENTITYDECL, true ).to_a.compact
84
+ match[0] = :entitydecl
85
+ ref = false
86
+ if match[1] == '%'
87
+ ref = true
88
+ match.delete_at 1
89
+ end
90
+ # Now we have to sort out what kind of entity reference this is
91
+ if match[2] == 'SYSTEM'
92
+ # External reference
93
+ match[3] = match[3][1..-2] # PUBID
94
+ match.delete_at(4) if match.size > 4 # Chop out NDATA decl
95
+ # match is [ :entity, name, SYSTEM, pubid(, ndata)? ]
96
+ elsif match[2] == 'PUBLIC'
97
+ # External reference
98
+ match[3] = match[3][1..-2] # PUBID
99
+ match[4] = match[4][1..-2] # HREF
100
+ # match is [ :entity, name, PUBLIC, pubid, href ]
101
+ else
102
+ match[2] = match[2][1..-2]
103
+ match.pop if match.size == 4
104
+ # match is [ :entity, name, value ]
105
+ end
106
+ match << '%' if ref
107
+ return match
108
+ when ATTLISTDECL_START
109
+ md = @source.match( ATTLISTDECL_PATTERN, true )
110
+ raise REXML::ParseException.new( "Bad ATTLIST declaration!", @source ) if md.nil?
111
+ element = md[1]
112
+ contents = md[0]
113
+
114
+ pairs = {}
115
+ values = md[0].scan( ATTDEF_RE )
116
+ values.each do |attdef|
117
+ unless attdef[3] == "#IMPLIED"
118
+ attdef.compact!
119
+ val = attdef[3]
120
+ val = attdef[4] if val == "#FIXED "
121
+ pairs[attdef[0]] = val
122
+ end
123
+ end
124
+ return [ :attlistdecl, element, pairs, contents ]
125
+ when NOTATIONDECL_START
126
+ md = nil
127
+ if @source.match( PUBLIC )
128
+ md = @source.match( PUBLIC, true )
129
+ elsif @source.match( SYSTEM )
130
+ md = @source.match( SYSTEM, true )
131
+ else
132
+ raise REXML::ParseException.new( "error parsing notation: no matching pattern", @source )
133
+ end
134
+ return [ :notationdecl, md[1], md[2], md[3] ]
135
+ when CDATA_END
136
+ @document_status = :after_doctype
137
+ @source.match( CDATA_END, true )
138
+ return [ :end_doctype ]
139
+ end
140
+ end
141
+ begin
142
+ if @source.buffer[0] == ?<
143
+ if @source.buffer[1] == ?/
144
+ last_tag, line_no = @tags.pop
145
+ #md = @source.match_to_consume( '>', CLOSE_MATCH)
146
+ md = @source.match( CLOSE_MATCH, true )
147
+ raise REXML::ParseException.new("Missing end tag for "+
148
+ "'#{last_tag}' (line #{line_no}) (got \"#{md[1]}\")",
149
+ @source) unless last_tag == md[1]
150
+ return [ :end_element, last_tag ]
151
+ elsif @source.buffer[1] == ?!
152
+ md = @source.match(/\A(\s*[^>]*>)/um)
153
+ raise REXML::ParseException.new("Malformed node", @source) unless md
154
+ if md[0][2] == ?-
155
+ md = @source.match( COMMENT_PATTERN, true )
156
+ return [ :comment, md[1] ] if md
157
+ else
158
+ md = @source.match( CDATA_PATTERN, true )
159
+ return [ :cdata, md[1] ] if md
160
+ end
161
+ raise REXML::ParseException.new( "Declarations can only occur "+
162
+ "in the doctype declaration.", @source)
163
+ elsif @source.buffer[1] == ??
164
+ md = @source.match( INSTRUCTION_PATTERN, true )
165
+ return [ :processing_instruction, md[1], md[2] ] if md
166
+ raise REXML::ParseException.new( "Bad instruction declaration",
167
+ @source)
168
+ else
169
+ # Get the next tag
170
+ md = @source.match(TAG_MATCH, true)
171
+ raise REXML::ParseException.new("malformed XML: missing tag start", @source) unless md
172
+ attrs = []
173
+ if md[2].size > 0
174
+ attrs = md[2].scan( ATTRIBUTE_PATTERN )
175
+ raise REXML::ParseException.new("error parsing attributes: [#{attrs.join ', '}], excess = \"#$'\"",
176
+ @source) if $' and $'.strip.size > 0
177
+ end
178
+
179
+ if md[4]
180
+ @closed = md[1]
181
+ else
182
+ cl = @source.current_line
183
+ @tags.push([md[1], cl && cl[2]])
184
+ end
185
+ attributes = {}
186
+ attrs.each { |a,b,c| attributes[a] = c }
187
+ return [ :start_element, md[1], attributes, md[0],
188
+ @source.respond_to?(:last_match_offset) && @source.last_match_offset ]
189
+ end
190
+ else
191
+ md = @source.match( TEXT_PATTERN, true )
192
+ if md[0].length == 0
193
+ @source.match( /(\s+)/, true )
194
+ end
195
+ #return [ :text, "" ] if md[0].length == 0
196
+ # unnormalized = Text::unnormalize( md[1], self )
197
+ # return PullEvent.new( :text, md[1], unnormalized )
198
+ return [ :text, md[1] ]
199
+ end
200
+ rescue REXML::ParseException
201
+ raise
202
+ rescue Exception, NameError => error
203
+ raise REXML::ParseException.new( "Exception parsing",
204
+ @source, self, (error ? error : $!) )
205
+ end
206
+ return [ :dummy ]
207
+ end
208
+ end
209
+
210
+ class TreeParser
211
+ def parse
212
+ tag_stack = []
213
+ in_doctype = false
214
+ entities = nil
215
+ begin
216
+ while true
217
+ event = @parser.pull
218
+ case event[0]
219
+ when :end_document
220
+ return
221
+ when :start_element
222
+ tag_stack.push(event[1])
223
+ # find the observers for namespaces
224
+ @build_context = @build_context.add_element( event[1], event[2] )
225
+ @build_context.instance_variable_set("@start_tag_source", event[3])
226
+ @build_context.instance_variable_set("@source_offset", event[4])
227
+ when :end_element
228
+ tag_stack.pop
229
+ @build_context = @build_context.parent
230
+ when :text
231
+ if not in_doctype
232
+ if @build_context[-1].instance_of? Text
233
+ @build_context[-1] << event[1]
234
+ else
235
+ @build_context.add(
236
+ Text.new( event[1], @build_context.whitespace, nil, true )
237
+ ) unless (
238
+ event[1].strip.size==0 and
239
+ @build_context.ignore_whitespace_nodes
240
+ )
241
+ end
242
+ end
243
+ when :comment
244
+ c = Comment.new( event[1] )
245
+ @build_context.add( c )
246
+ when :cdata
247
+ c = CData.new( event[1] )
248
+ @build_context.add( c )
249
+ when :processing_instruction
250
+ @build_context.add( Instruction.new( event[1], event[2] ) )
251
+ when :end_doctype
252
+ in_doctype = false
253
+ entities.each { |k,v| entities[k] = @build_context.entities[k].value }
254
+ @build_context = @build_context.parent
255
+ when :start_doctype
256
+ doctype = DocType.new( event[1..-1], @build_context )
257
+ @build_context = doctype
258
+ entities = {}
259
+ in_doctype = true
260
+ when :attlistdecl
261
+ n = AttlistDecl.new( event[1..-1] )
262
+ @build_context.add( n )
263
+ when :externalentity
264
+ n = ExternalEntity.new( event[1] )
265
+ @build_context.add( n )
266
+ when :elementdecl
267
+ n = ElementDecl.new( event[1] )
268
+ @build_context.add(n)
269
+ when :entitydecl
270
+ entities[ event[1] ] = event[2] unless event[2] =~ /PUBLIC|SYSTEM/
271
+ @build_context.add(Entity.new(event))
272
+ when :notationdecl
273
+ n = NotationDecl.new( *event[1..-1] )
274
+ @build_context.add( n )
275
+ when :xmldecl
276
+ x = XMLDecl.new( event[1], event[2], event[3] )
277
+ @build_context.add( x )
278
+ end
279
+ end
280
+ rescue REXML::Validation::ValidationException
281
+ raise
282
+ rescue
283
+ raise ParseException.new( $!.message, @parser.source, @parser, $! )
284
+ end
285
+ end
286
+ end
287
+ end
288
+ end
289
+
290
+ module Hobo::Dryml
291
+
292
+ class RexSource < REXML::Source
293
+
294
+ def initialize(src)
295
+ super(src)
296
+ @buffer_offset = 0
297
+ end
298
+
299
+ attr_reader :last_match_offset
300
+
301
+ def remember_match(m)
302
+ if m
303
+ @last_match = m
304
+ @last_match_offset = @buffer_offset + m.begin(0)
305
+ @orig[@last_match_offset..@last_match_offset+m[0].length] == @buffer[m.begin(0)..m.end(0)]
306
+ end
307
+ m
308
+ end
309
+
310
+ def advance_buffer(md)
311
+ @buffer = md.post_match
312
+ @buffer_offset += md.end(0)
313
+ end
314
+
315
+ def scan(pattern, cons=false)
316
+ raise '!'
317
+ return nil if @buffer.nil?
318
+ rv = @buffer.scan(pattern)
319
+ if cons and rv.size > 0
320
+ advance_buffer(Regexp.last_match)
321
+ end
322
+ rv
323
+ end
324
+
325
+ def consume( pattern )
326
+ md = remember_match(pattern.match( @buffer ))
327
+ if md
328
+ advance_buffer(md)
329
+ @buffer
330
+ end
331
+ end
332
+
333
+ def match(pattern, cons=false)
334
+ md = remember_match(pattern.match(@buffer))
335
+ advance_buffer(md) if cons and md
336
+ return md
337
+ end
338
+
339
+ def current_line
340
+ pos = last_match_offset
341
+ [0, 0, @orig[0..pos].count("\n") + 1]
342
+ end
343
+
344
+ end
345
+ end