hobo 0.7.3 → 0.7.4
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.
- 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
|