hobo 0.7.3 → 0.7.4
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/hobo +1 -1
- data/hobo_files/plugin/CHANGES.txt +302 -0
- data/hobo_files/plugin/generators/hobo_front_controller/templates/index.dryml +2 -9
- data/hobo_files/plugin/generators/hobo_model/templates/model.rb +1 -1
- data/hobo_files/plugin/generators/hobo_model_resource/hobo_model_resource_generator.rb +0 -2
- data/hobo_files/plugin/generators/hobo_rapid/templates/hobo-rapid.js +76 -46
- data/hobo_files/plugin/generators/hobo_rapid/templates/lowpro.js +25 -18
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/clean/public/stylesheets/application.css +29 -11
- data/hobo_files/plugin/generators/hobo_user_model/templates/model.rb +2 -2
- data/hobo_files/plugin/init.rb +0 -1
- data/hobo_files/plugin/lib/active_record/has_many_association.rb +3 -0
- data/hobo_files/plugin/lib/hobo.rb +12 -8
- data/hobo_files/plugin/lib/hobo/bundle.rb +1 -1
- data/hobo_files/plugin/lib/hobo/dryml/dryml_builder.rb +1 -1
- data/hobo_files/plugin/lib/hobo/dryml/parser/attribute.rb +41 -0
- data/hobo_files/plugin/lib/hobo/dryml/parser/base_parser.rb +253 -0
- data/hobo_files/plugin/lib/hobo/dryml/parser/document.rb +26 -0
- data/hobo_files/plugin/lib/hobo/dryml/parser/element.rb +27 -0
- data/hobo_files/plugin/lib/hobo/dryml/parser/elements.rb +45 -0
- data/hobo_files/plugin/lib/hobo/dryml/parser/source.rb +58 -0
- data/hobo_files/plugin/lib/hobo/dryml/parser/text.rb +13 -0
- data/hobo_files/plugin/lib/hobo/dryml/parser/tree_parser.rb +67 -0
- data/hobo_files/plugin/lib/hobo/dryml/scoped_variables.rb +10 -5
- data/hobo_files/plugin/lib/hobo/dryml/template.rb +48 -27
- data/hobo_files/plugin/lib/hobo/dryml/template_environment.rb +28 -13
- data/hobo_files/plugin/lib/hobo/hobo_helper.rb +3 -1
- data/hobo_files/plugin/lib/hobo/model.rb +70 -10
- data/hobo_files/plugin/lib/hobo/model_controller.rb +49 -34
- data/hobo_files/plugin/lib/hobo/model_router.rb +10 -2
- data/hobo_files/plugin/lib/hobo/rapid_helper.rb +1 -0
- data/hobo_files/plugin/lib/hobo/scopes.rb +15 -0
- data/hobo_files/plugin/lib/hobo/scopes/apply_scopes.rb +23 -0
- data/hobo_files/plugin/lib/hobo/scopes/association_proxy_extensions.rb +4 -2
- data/hobo_files/plugin/lib/hobo/scopes/automatic_scopes.rb +34 -7
- data/hobo_files/plugin/lib/hobo/scopes/defined_scope_proxy_extender.rb +3 -1
- data/hobo_files/plugin/lib/hobo/scopes/scoped_proxy.rb +1 -5
- data/hobo_files/plugin/taglibs/rapid.dryml +33 -24
- data/hobo_files/plugin/taglibs/rapid_editing.dryml +6 -5
- data/hobo_files/plugin/taglibs/rapid_forms.dryml +37 -31
- data/hobo_files/plugin/taglibs/rapid_generics.dryml +68 -27
- data/hobo_files/plugin/taglibs/rapid_navigation.dryml +5 -8
- data/hobo_files/plugin/taglibs/rapid_pages.dryml +71 -47
- data/hobo_files/plugin/taglibs/rapid_plus.dryml +4 -5
- data/hobo_files/plugin/taglibs/rapid_support.dryml +11 -4
- metadata +23 -6
- data/hobo_files/plugin/lib/rexml.rb +0 -443
@@ -1,8 +1,8 @@
|
|
1
1
|
LowPro = {};
|
2
2
|
LowPro.Version = '0.5';
|
3
|
-
LowPro.CompatibleWithPrototype = '1.6
|
3
|
+
LowPro.CompatibleWithPrototype = '1.6';
|
4
4
|
|
5
|
-
if (Prototype.Version
|
5
|
+
if (Prototype.Version.indexOf(LowPro.CompatibleWithPrototype) != 0 && window.console && window.console.warn)
|
6
6
|
console.warn("This version of Low Pro is tested with Prototype " + LowPro.CompatibleWithPrototype +
|
7
7
|
" it may not work as expected with this version (" + Prototype.Version + ")");
|
8
8
|
|
@@ -15,19 +15,19 @@ DOM = {};
|
|
15
15
|
// DOMBuilder for prototype
|
16
16
|
DOM.Builder = {
|
17
17
|
tagFunc : function(tag) {
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
18
|
+
return function() {
|
19
|
+
var attrs, children;
|
20
|
+
if (arguments.length>0) {
|
21
|
+
if (arguments[0].constructor == Object) {
|
22
|
+
attrs = arguments[0];
|
23
|
+
children = Array.prototype.slice.call(arguments, 1);
|
24
|
+
} else {
|
25
|
+
children = arguments;
|
26
|
+
};
|
27
|
+
children = $A(children).flatten()
|
28
|
+
}
|
29
|
+
return DOM.Builder.create(tag, attrs, children);
|
30
|
+
};
|
31
31
|
},
|
32
32
|
create : function(tag, attrs, children) {
|
33
33
|
attrs = attrs || {}; children = children || []; tag = tag.toLowerCase();
|
@@ -71,7 +71,8 @@ DOM.Builder.fromHTML = function(html) {
|
|
71
71
|
// Event.onReady(callbackFunction);
|
72
72
|
Object.extend(Event, {
|
73
73
|
onReady : function(f) {
|
74
|
-
document.
|
74
|
+
if (document.body) f();
|
75
|
+
else document.observe('dom:loaded', f);
|
75
76
|
}
|
76
77
|
});
|
77
78
|
|
@@ -96,7 +97,7 @@ Event.addBehavior = function(rules) {
|
|
96
97
|
Ajax.Responders.register({
|
97
98
|
onComplete : function() {
|
98
99
|
if (Event.addBehavior.reassignAfterAjax)
|
99
|
-
setTimeout(function() { ab.
|
100
|
+
setTimeout(function() { ab.reload() }, 10);
|
100
101
|
}
|
101
102
|
});
|
102
103
|
ab.responderApplied = true;
|
@@ -145,6 +146,12 @@ Object.extend(Event.addBehavior, {
|
|
145
146
|
this.cache = [];
|
146
147
|
},
|
147
148
|
|
149
|
+
reload: function() {
|
150
|
+
var ab = Event.addBehavior;
|
151
|
+
ab.unload();
|
152
|
+
ab.load(ab.rules);
|
153
|
+
},
|
154
|
+
|
148
155
|
_wrapObserver: function(observer) {
|
149
156
|
return function(event) {
|
150
157
|
if (observer.call(this, event) === false) event.stop();
|
@@ -277,7 +284,7 @@ Remote.Form = Behavior.create(Remote.Base, {
|
|
277
284
|
onclick : function(e) {
|
278
285
|
var sourceElement = e.element();
|
279
286
|
|
280
|
-
if (sourceElement.nodeName.toLowerCase()
|
287
|
+
if (['input', 'button'].include(sourceElement.nodeName.toLowerCase()) &&
|
281
288
|
sourceElement.type == 'submit')
|
282
289
|
this._submitButton = sourceElement;
|
283
290
|
},
|
@@ -53,7 +53,7 @@ input.file_upload {
|
|
53
53
|
.actions {height: 100%; overflow:hidden; font-size: 11px;}
|
54
54
|
|
55
55
|
.flash {
|
56
|
-
margin:
|
56
|
+
margin: 0 40px 10px; padding: 10px 30px; border-width: 2px 0;
|
57
57
|
color: white;
|
58
58
|
}
|
59
59
|
.flash.notice {border: 1px solid #829862; background: #92ab6e; text-shadow: #728852 1px 1px 0;}
|
@@ -91,9 +91,12 @@ input.file_upload {
|
|
91
91
|
.content-header, .content-body {padding-bottom: 15px;}
|
92
92
|
.content-footer {padding-bottom: 20px;}
|
93
93
|
|
94
|
+
.page-content { margin-top: 20px; }
|
95
|
+
|
94
96
|
/* aside layout */
|
95
97
|
body.aside-layout {width: 960px;}
|
96
|
-
.aside-layout .page-content {height: 100%; overflow: hidden;}
|
98
|
+
.aside-layout .page-content {height: 100%; overflow: hidden; margin-top: 0px;}
|
99
|
+
.aside-layout .main-content {margin-top: 20px;}
|
97
100
|
.main-content {float: left; width: 670px;}
|
98
101
|
.aside {float: right; width: 220px; padding: 20px 30px; background: #E5E5E5;}
|
99
102
|
.aside-content {
|
@@ -106,7 +109,7 @@ body.aside-layout {width: 960px;}
|
|
106
109
|
.aside, .main-content {padding-bottom: 10000px; margin-bottom: -10000px;}
|
107
110
|
|
108
111
|
|
109
|
-
.page-header {position: relative; margin: 20px
|
112
|
+
.page-header {position: relative; margin-top: 20px; padding: 20px 0 0; color: white; background: black;}
|
110
113
|
.page-header h1 {
|
111
114
|
margin: 0; padding: 0 30px 30px;
|
112
115
|
font-family: "Arial Black", Tahoma, Arial, sans-serif; font-size: 36px; letter-spacing: -1.5pt;
|
@@ -154,7 +157,6 @@ ul.main-nav {float: left; margin: 0 10px;}
|
|
154
157
|
float: left;
|
155
158
|
margin-left: 0; padding-left: 20px;
|
156
159
|
color: #ddd;
|
157
|
-
text-shadow: #444 1px 1px 0;
|
158
160
|
list-style: none;
|
159
161
|
}
|
160
162
|
.account-nav a {font-weight: bold;}
|
@@ -186,9 +188,9 @@ form .actions {margin: 30px 0; width: 100%; text-align: center;}
|
|
186
188
|
.aside-content .collection {padding-bottom: 10px;}
|
187
189
|
|
188
190
|
.content-header .creation-details, .content-header .primary-collection-count {font-size: 11px; line-height: 11px;}
|
189
|
-
.content-header .creator {margin-right:
|
191
|
+
.content-header .creator {margin-right: 15px;}
|
190
192
|
.content-header .created-at {color: #444;}
|
191
|
-
.content-header .primary-collection-count {
|
193
|
+
.content-header .primary-collection-count {font-weight: bold;}
|
192
194
|
|
193
195
|
.new-in-collection-page .content-header h2 {margin-top: 6px; font-size: 14px;}
|
194
196
|
.new-in-collection-page .content-header h2, .new-in-collection-page .content-header h2 a {color: #222;}
|
@@ -203,18 +205,21 @@ form .actions {margin: 30px 0; width: 100%; text-align: center;}
|
|
203
205
|
/* styling of generic elements */
|
204
206
|
.creator {font-weight: bold;}
|
205
207
|
.card {
|
206
|
-
clear: both;
|
207
208
|
height: 100%; overflow: hidden;
|
208
|
-
margin
|
209
|
+
margin: 10px 0; padding: 12px 20px; border: 1px solid #e8e8e8;
|
209
210
|
background: #f5f5f5;
|
210
211
|
}
|
212
|
+
.card h3 {margin-top: 0;}
|
211
213
|
.card a {background: #f5f5f5;}
|
212
214
|
.card .creation-details {
|
213
215
|
display: block; color: #333; font-size: 11px;
|
214
216
|
}
|
215
217
|
.card .datetime {color: #666;}
|
218
|
+
.card a.edit { float: right;}
|
219
|
+
.card .delete-button { float: right;}
|
220
|
+
div.ordering-handle { float: left; background: #ccc; color: white; margin-right: 5px; cursor: move; padding: 0 2px;}
|
216
221
|
|
217
|
-
.card.content {
|
222
|
+
.card.content.with-owner {
|
218
223
|
padding: 0; margin: 10px 0 30px; border: none;
|
219
224
|
background: none;
|
220
225
|
font-size: 11px;
|
@@ -224,7 +229,7 @@ form .actions {margin: 30px 0; width: 100%; text-align: center;}
|
|
224
229
|
line-height: 14px;
|
225
230
|
}
|
226
231
|
.card.content .creation-details .created-at {display: block;}
|
227
|
-
.card.content .content {
|
232
|
+
.card.content.with-owner .content {
|
228
233
|
float: right; width: 72%;
|
229
234
|
}
|
230
235
|
ul.collection li {clear: both; margin-left: 0; list-style: none;}
|
@@ -256,11 +261,23 @@ ul.collection li {clear: both; margin-left: 0; list-style: none;}
|
|
256
261
|
.table-plus table td {
|
257
262
|
padding: 6px 10px; border-bottom: 1px solid #e2e2e2; color: #666;
|
258
263
|
}
|
259
|
-
.table-plus table td input.button {padding: 1px; margin-left: 10px; }
|
264
|
+
.table-plus table td input.button, .collection .button {padding: 1px 3px; margin-left: 10px; margin-top: 0;}
|
260
265
|
.table-plus table td.controls {width: 100px;}
|
261
266
|
.table-plus .even {background: #f8f8f8;}
|
262
267
|
.table-plus a {background: none;}
|
263
268
|
|
269
|
+
/* <select-many> */
|
270
|
+
|
271
|
+
div.select-many {border-top: 1px dotted #999;}
|
272
|
+
div.select-many .items {margin-bottom: 10px;}
|
273
|
+
div.select-many .item {
|
274
|
+
overflow:hidden; height: 100%; font-weight: bold;
|
275
|
+
border-bottom: 1px dotted #999; padding: 5px 10px; /*margin: 5px 25px 5px 0;*/
|
276
|
+
}
|
277
|
+
div.select-many .item span { float: left; }
|
278
|
+
div.select-many .item .remove-item { float: right; }
|
279
|
+
|
280
|
+
|
264
281
|
/*******************************************************/
|
265
282
|
/* these styles are for the generated front index page */
|
266
283
|
/* you can delete them if you over-ride it */
|
@@ -273,3 +290,4 @@ ul.collection li {clear: both; margin-left: 0; list-style: none;}
|
|
273
290
|
font-size: 18px; line-height: 27px;
|
274
291
|
}
|
275
292
|
.front-page .content-body li {margin-left: 0; list-style: none;}
|
293
|
+
|
@@ -1,6 +1,6 @@
|
|
1
1
|
class <%= class_name %> < ActiveRecord::Base
|
2
2
|
|
3
|
-
hobo_user_model
|
3
|
+
hobo_user_model # Don't put anything above this
|
4
4
|
|
5
5
|
fields do
|
6
6
|
username :string, :login => true, :name => true
|
@@ -17,7 +17,7 @@ class <%= class_name %> < ActiveRecord::Base
|
|
17
17
|
# def super_user?; true; end
|
18
18
|
|
19
19
|
def creatable_by?(creator)
|
20
|
-
|
20
|
+
creator.administrator? || !administrator
|
21
21
|
end
|
22
22
|
|
23
23
|
def updatable_by?(updater, new)
|
data/hobo_files/plugin/init.rb
CHANGED
@@ -28,14 +28,17 @@ module ActiveRecord::Associations
|
|
28
28
|
proxy_reflection.klass
|
29
29
|
end
|
30
30
|
|
31
|
+
|
31
32
|
def origin
|
32
33
|
proxy_owner
|
33
34
|
end
|
34
35
|
|
36
|
+
|
35
37
|
def origin_attribute
|
36
38
|
proxy_reflection.association_name
|
37
39
|
end
|
38
40
|
|
41
|
+
|
39
42
|
private
|
40
43
|
|
41
44
|
def set_reverse_association(object)
|
@@ -171,9 +171,13 @@ module Hobo
|
|
171
171
|
if object.is_a?(Class) and object < ActiveRecord::Base
|
172
172
|
object = object.new
|
173
173
|
object.set_creator(person)
|
174
|
-
elsif
|
175
|
-
|
176
|
-
|
174
|
+
elsif (refl = object.try.proxy_reflection) && refl.macro == :has_many
|
175
|
+
if Hobo.simple_has_many_association?(object)
|
176
|
+
object = object.new
|
177
|
+
object.set_creator(person)
|
178
|
+
else
|
179
|
+
return false
|
180
|
+
end
|
177
181
|
end
|
178
182
|
check_permission(:create, person, object)
|
179
183
|
end
|
@@ -210,13 +214,13 @@ module Hobo
|
|
210
214
|
object.send("#{field}_editable_by?", person)
|
211
215
|
elsif object.has_hobo_method?(:editable_by?)
|
212
216
|
check_permission(:edit, person, object)
|
217
|
+
elsif refl._?.macro == :has_many
|
218
|
+
# The below technique to figure out edit permission based on
|
219
|
+
# update permission doesn't work for has_many associations
|
220
|
+
false
|
213
221
|
else
|
214
222
|
# Fake an edit test by setting the field in question to
|
215
223
|
# Hobo::Undefined and then testing for update permission
|
216
|
-
|
217
|
-
# This technique is not suitable for has_many associations
|
218
|
-
return false if refl._?.macro == :has_many
|
219
|
-
|
220
224
|
current = object.send(field)
|
221
225
|
new = object.duplicate
|
222
226
|
|
@@ -333,7 +337,7 @@ module Hobo
|
|
333
337
|
when :edit; :editable_by?
|
334
338
|
when :view; :viewable_by?
|
335
339
|
end
|
336
|
-
p = if object.has_hobo_method?(obj_method)
|
340
|
+
p = if (obj_method.respond_to?(:has_hobo_method) ? object.has_hobo_method?(obj_method) : object.respond_to?(obj_method))
|
337
341
|
begin
|
338
342
|
object.send(obj_method, person, *args)
|
339
343
|
rescue Hobo::UndefinedAccessError
|
@@ -167,7 +167,7 @@ module ::Hobo
|
|
167
167
|
def create_controllers
|
168
168
|
bundle = self
|
169
169
|
self.class.controller_declarations.each do |model_name, block|
|
170
|
-
klass = make_class("#{new_name_for(model_name).to_s.pluralize}Controller", ApplicationController) do
|
170
|
+
klass = make_class("#{new_name_for(model_name).to_s.pluralize}Controller", ::ApplicationController) do
|
171
171
|
hobo_model_controller
|
172
172
|
end
|
173
173
|
klass.class_eval(&block)
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Hobo::Dryml::Parser
|
2
|
+
|
3
|
+
class Attribute < REXML::Attribute
|
4
|
+
|
5
|
+
def initialize(first, second=nil, parent=nil)
|
6
|
+
super
|
7
|
+
if first.is_a?(String) && second == true
|
8
|
+
@value = true
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def value
|
13
|
+
if has_rhs?
|
14
|
+
super
|
15
|
+
else
|
16
|
+
element.document.default_attribute_value
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_string
|
21
|
+
if has_rhs?
|
22
|
+
super
|
23
|
+
else
|
24
|
+
@expanded_name
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def has_rhs?
|
29
|
+
@value != true
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
# Override to supress Text.check call
|
34
|
+
def element=( element )
|
35
|
+
@element = element
|
36
|
+
self
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,253 @@
|
|
1
|
+
module Hobo::Dryml::Parser
|
2
|
+
|
3
|
+
class BaseParser < REXML::Parsers::BaseParser
|
4
|
+
|
5
|
+
REX_3_1_7_1 = REXML::VERSION == "3.1.7.1"
|
6
|
+
|
7
|
+
DRYML_NAME_STR = "#{NCNAME_STR}(?::(?:#{NCNAME_STR})?)?"
|
8
|
+
DRYML_ATTRIBUTE_PATTERN = if REX_3_1_7_1
|
9
|
+
/\s*(#{NAME_STR})(?:\s*=\s*(["'])(.*?)\2)?/um
|
10
|
+
else
|
11
|
+
/\s*(#{NAME_STR})(?:\s*=\s*(["'])(.*?)\4)?/um
|
12
|
+
end
|
13
|
+
DRYML_TAG_MATCH = if REX_3_1_7_1
|
14
|
+
/^<((?>#{DRYML_NAME_STR}))\s*((?>\s+#{NAME_STR}(?:\s*=\s*(["']).*?\3)?)*)\s*(\/)?>/um
|
15
|
+
else
|
16
|
+
/^<((?>#{DRYML_NAME_STR}))\s*((?>\s+#{NAME_STR}(?:\s*=\s*(["']).*?\5)?)*)\s*(\/)?>/um
|
17
|
+
end
|
18
|
+
DRYML_CLOSE_MATCH = /^\s*<\/(#{DRYML_NAME_STR})\s*>/um
|
19
|
+
|
20
|
+
# For compatibility with REXML 3.1.7.3
|
21
|
+
IDENTITY = /^([!\*\w\-]+)(\s+#{NCNAME_STR})?(\s+["'](.*?)['"])?(\s+['"](.*?)["'])?/u
|
22
|
+
|
23
|
+
def pull
|
24
|
+
if @closed
|
25
|
+
x, @closed = @closed, nil
|
26
|
+
return [ :end_element, x, false ]
|
27
|
+
end
|
28
|
+
return [ :end_document ] if empty?
|
29
|
+
return @stack.shift if @stack.size > 0
|
30
|
+
#STDERR.puts @source.encoding
|
31
|
+
@source.read if @source.buffer.size<2
|
32
|
+
#STDERR.puts "BUFFER = #{@source.buffer.inspect}"
|
33
|
+
if @document_status == nil
|
34
|
+
#@source.consume( /^\s*/um )
|
35
|
+
word = @source.match( /^((?:\s+)|(?:<[^>]*>))/um ) #word = @source.match(/(<[^>]*)>/um)
|
36
|
+
word = word[1] unless word.nil?
|
37
|
+
#STDERR.puts "WORD = #{word.inspect}"
|
38
|
+
case word
|
39
|
+
when COMMENT_START
|
40
|
+
return [ :comment, @source.match( COMMENT_PATTERN, true )[1] ]
|
41
|
+
when XMLDECL_START
|
42
|
+
#STDERR.puts "XMLDECL"
|
43
|
+
results = @source.match( XMLDECL_PATTERN, true )[1]
|
44
|
+
version = VERSION.match( results )
|
45
|
+
version = version[1] unless version.nil?
|
46
|
+
encoding = ENCODING.match(results)
|
47
|
+
encoding = encoding[1] unless encoding.nil?
|
48
|
+
@source.encoding = encoding
|
49
|
+
standalone = STANDALONE.match(results)
|
50
|
+
standalone = standalone[1] unless standalone.nil?
|
51
|
+
return [ :xmldecl, version, encoding, standalone ]
|
52
|
+
when INSTRUCTION_START
|
53
|
+
return [ :processing_instruction, *@source.match(INSTRUCTION_PATTERN, true)[1,2] ]
|
54
|
+
when DOCTYPE_START
|
55
|
+
md = @source.match( DOCTYPE_PATTERN, true )
|
56
|
+
#@nsstack.unshift(curr_ns=Set.new)
|
57
|
+
identity = md[1]
|
58
|
+
close = md[2]
|
59
|
+
identity =~ IDENTITY
|
60
|
+
name = $1
|
61
|
+
raise REXML::ParseException.new("DOCTYPE is missing a name") if name.nil?
|
62
|
+
pub_sys = $2.nil? ? nil : $2.strip
|
63
|
+
long_name = $4.nil? ? nil : $4.strip
|
64
|
+
uri = $6.nil? ? nil : $6.strip
|
65
|
+
args = [ :start_doctype, name, pub_sys, long_name, uri ]
|
66
|
+
if close == ">"
|
67
|
+
@document_status = :after_doctype
|
68
|
+
@source.read if @source.buffer.size<2
|
69
|
+
md = @source.match(/^\s*/um, true)
|
70
|
+
@stack << [ :end_doctype ]
|
71
|
+
else
|
72
|
+
@document_status = :in_doctype
|
73
|
+
end
|
74
|
+
return args
|
75
|
+
when /^\s+/
|
76
|
+
else
|
77
|
+
@document_status = :after_doctype
|
78
|
+
@source.read if @source.buffer.size<2
|
79
|
+
md = @source.match(/\s*/um, true)
|
80
|
+
if @source.encoding == "UTF-8"
|
81
|
+
if @source.buffer.respond_to? :force_encoding
|
82
|
+
@source.buffer.force_encoding(Encoding::UTF_8)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
if @document_status == :in_doctype
|
88
|
+
md = @source.match(/\s*(.*?>)/um)
|
89
|
+
case md[1]
|
90
|
+
when SYSTEMENTITY
|
91
|
+
match = @source.match( SYSTEMENTITY, true )[1]
|
92
|
+
return [ :externalentity, match ]
|
93
|
+
|
94
|
+
when ELEMENTDECL_START
|
95
|
+
return [ :elementdecl, @source.match( ELEMENTDECL_PATTERN, true )[1] ]
|
96
|
+
|
97
|
+
when ENTITY_START
|
98
|
+
match = @source.match( ENTITYDECL, true ).to_a.compact
|
99
|
+
match[0] = :entitydecl
|
100
|
+
ref = false
|
101
|
+
if match[1] == '%'
|
102
|
+
ref = true
|
103
|
+
match.delete_at 1
|
104
|
+
end
|
105
|
+
# Now we have to sort out what kind of entity reference this is
|
106
|
+
if match[2] == 'SYSTEM'
|
107
|
+
# External reference
|
108
|
+
match[3] = match[3][1..-2] # PUBID
|
109
|
+
match.delete_at(4) if match.size > 4 # Chop out NDATA decl
|
110
|
+
# match is [ :entity, name, SYSTEM, pubid(, ndata)? ]
|
111
|
+
elsif match[2] == 'PUBLIC'
|
112
|
+
# External reference
|
113
|
+
match[3] = match[3][1..-2] # PUBID
|
114
|
+
match[4] = match[4][1..-2] # HREF
|
115
|
+
# match is [ :entity, name, PUBLIC, pubid, href ]
|
116
|
+
else
|
117
|
+
match[2] = match[2][1..-2]
|
118
|
+
match.pop if match.size == 4
|
119
|
+
# match is [ :entity, name, value ]
|
120
|
+
end
|
121
|
+
match << '%' if ref
|
122
|
+
return match
|
123
|
+
when ATTLISTDECL_START
|
124
|
+
md = @source.match( ATTLISTDECL_PATTERN, true )
|
125
|
+
raise REXML::ParseException.new( "Bad ATTLIST declaration!", @source ) if md.nil?
|
126
|
+
element = md[1]
|
127
|
+
contents = md[0]
|
128
|
+
|
129
|
+
pairs = {}
|
130
|
+
values = md[0].scan( ATTDEF_RE )
|
131
|
+
values.each do |attdef|
|
132
|
+
unless attdef[3] == "#IMPLIED"
|
133
|
+
attdef.compact!
|
134
|
+
val = attdef[3]
|
135
|
+
val = attdef[4] if val == "#FIXED "
|
136
|
+
pairs[attdef[0]] = val
|
137
|
+
if attdef[0] =~ /^xmlns:(.*)/
|
138
|
+
#@nsstack[0] << $1
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
return [ :attlistdecl, element, pairs, contents ]
|
143
|
+
when NOTATIONDECL_START
|
144
|
+
md = nil
|
145
|
+
if @source.match( PUBLIC )
|
146
|
+
md = @source.match( PUBLIC, true )
|
147
|
+
vals = [md[1],md[2],md[4],md[6]]
|
148
|
+
elsif @source.match( SYSTEM )
|
149
|
+
md = @source.match( SYSTEM, true )
|
150
|
+
vals = [md[1],md[2],nil,md[4]]
|
151
|
+
else
|
152
|
+
raise REXML::ParseException.new( "error parsing notation: no matching pattern", @source )
|
153
|
+
end
|
154
|
+
return [ :notationdecl, *vals ]
|
155
|
+
when CDATA_END
|
156
|
+
@document_status = :after_doctype
|
157
|
+
@source.match( CDATA_END, true )
|
158
|
+
return [ :end_doctype ]
|
159
|
+
end
|
160
|
+
end
|
161
|
+
begin
|
162
|
+
if @source.buffer[0] == ?<
|
163
|
+
if @source.buffer[1] == ?/
|
164
|
+
#@nsstack.shift
|
165
|
+
last_tag, line_no = @tags.pop
|
166
|
+
#md = @source.match_to_consume( '>', CLOSE_MATCH)
|
167
|
+
md = @source.match(DRYML_CLOSE_MATCH, true)
|
168
|
+
|
169
|
+
valid_end_tag = last_tag =~ /^#{Regexp.escape(md[1])}(:.*)?/
|
170
|
+
raise REXML::ParseException.new( "Missing end tag for "+
|
171
|
+
"'#{last_tag}' (line #{line_no}) (got \"#{md[1]}\")",
|
172
|
+
@source) unless valid_end_tag
|
173
|
+
return [ :end_element, last_tag, true ]
|
174
|
+
elsif @source.buffer[1] == ?!
|
175
|
+
md = @source.match(/\A(\s*[^>]*>)/um)
|
176
|
+
#STDERR.puts "SOURCE BUFFER = #{source.buffer}, #{source.buffer.size}"
|
177
|
+
raise REXML::ParseException.new("Malformed node", @source) unless md
|
178
|
+
if md[0][2] == ?-
|
179
|
+
md = @source.match( COMMENT_PATTERN, true )
|
180
|
+
|
181
|
+
case md[1]
|
182
|
+
when /--/, /-$/
|
183
|
+
raise REXML::ParseException.new("Malformed comment", @source)
|
184
|
+
end
|
185
|
+
|
186
|
+
return [ :comment, md[1] ] if md
|
187
|
+
else
|
188
|
+
md = @source.match( CDATA_PATTERN, true )
|
189
|
+
return [ :cdata, md[1] ] if md
|
190
|
+
end
|
191
|
+
raise REXML::ParseException.new( "Declarations can only occur "+
|
192
|
+
"in the doctype declaration.", @source)
|
193
|
+
elsif @source.buffer[1] == ??
|
194
|
+
md = @source.match( INSTRUCTION_PATTERN, true )
|
195
|
+
return [ :processing_instruction, md[1], md[2] ] if md
|
196
|
+
raise REXML::ParseException.new( "Bad instruction declaration",
|
197
|
+
@source)
|
198
|
+
else
|
199
|
+
# Get the next tag
|
200
|
+
md = @source.match(DRYML_TAG_MATCH, true)
|
201
|
+
unless md
|
202
|
+
# Check for missing attribute quotes
|
203
|
+
raise REXML::ParseException.new("missing attribute quote", @source) if @source.match(MISSING_ATTRIBUTE_QUOTES )
|
204
|
+
raise REXML::ParseException.new("malformed XML: missing tag start", @source)
|
205
|
+
|
206
|
+
end
|
207
|
+
attributes = {}
|
208
|
+
#@nsstack.unshift(curr_ns=Set.new)
|
209
|
+
if md[2].size > 0
|
210
|
+
attrs = md[2].scan(DRYML_ATTRIBUTE_PATTERN)
|
211
|
+
raise REXML::ParseException.new( "error parsing attributes: [#{attrs.join ', '}], excess = \"#$'\"", @source) if $' and $'.strip.size > 0
|
212
|
+
attrs.each { |a,b,c,d,e|
|
213
|
+
val = REX_3_1_7_1 ? c : e
|
214
|
+
if attributes.has_key? a
|
215
|
+
msg = "Duplicate attribute #{a.inspect}"
|
216
|
+
raise REXML::ParseException.new( msg, @source, self)
|
217
|
+
end
|
218
|
+
attributes[a] = val || true
|
219
|
+
}
|
220
|
+
end
|
221
|
+
|
222
|
+
if md[REX_3_1_7_1 ? 4 : 6]
|
223
|
+
@closed = md[1]
|
224
|
+
#@nsstack.shift
|
225
|
+
else
|
226
|
+
cl = @source.current_line
|
227
|
+
@tags.push( [md[1], cl && cl[2]] )
|
228
|
+
end
|
229
|
+
return [ :start_element, md[1], attributes, md[0],
|
230
|
+
@source.respond_to?(:last_match_offset) && @source.last_match_offset ]
|
231
|
+
end
|
232
|
+
else
|
233
|
+
md = @source.match( TEXT_PATTERN, true )
|
234
|
+
if md[0].length == 0
|
235
|
+
@source.match( /(\s+)/, true )
|
236
|
+
end
|
237
|
+
#STDERR.puts "GOT #{md[1].inspect}" unless md[0].length == 0
|
238
|
+
#return [ :text, "" ] if md[0].length == 0
|
239
|
+
# unnormalized = Text::unnormalize( md[1], self )
|
240
|
+
# return PullEvent.new( :text, md[1], unnormalized )
|
241
|
+
return [ :text, md[1] ]
|
242
|
+
end
|
243
|
+
rescue REXML::ParseException
|
244
|
+
raise
|
245
|
+
rescue Exception, NameError => error
|
246
|
+
raise REXML::ParseException.new( "Exception parsing",
|
247
|
+
@source, self, (error ? error : $!) )
|
248
|
+
end
|
249
|
+
return [ :dummy ]
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
end
|