masterview 0.2.5 → 0.3.0
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/CHANGELOG +31 -1
- data/README +70 -69
- data/RELEASE_NOTES +70 -64
- data/Rakefile +26 -27
- data/TODO +13 -29
- data/doc/about.html +246 -0
- data/doc/configuration.html +49 -36
- data/doc/developer.html +423 -41
- data/doc/directives.html +139 -51
- data/doc/guide.html +19 -9
- data/doc/index.html +90 -224
- data/doc/installation.html +36 -28
- data/doc/media_list.html +30 -20
- data/doc/simple_diagram.html +3 -5
- data/doc/stylesheets/masterview.css +16 -1
- data/examples/rails_app_config/masterview/settings.rb +2 -1
- data/init.rb +1 -1
- data/lib/#ChangeLog# +6 -0
- data/lib/masterview/analyzer.rb +48 -34
- data/lib/masterview/attr_string_parser.rb +5 -1
- data/lib/masterview/case_insensitive_hash.rb +69 -0
- data/lib/masterview/{pathname_extensions.rb → core_ext/pathname.rb} +0 -0
- data/lib/masterview/{string_extensions.rb → core_ext/string.rb} +0 -0
- data/lib/masterview/deprecated/directive_base.rb +362 -0
- data/lib/masterview/directive_base.rb +201 -179
- data/lib/masterview/directive_dsl.rb +457 -0
- data/lib/masterview/directive_helpers.rb +28 -141
- data/lib/masterview/directive_load_path.rb +388 -0
- data/lib/masterview/directive_metadata.rb +377 -0
- data/lib/masterview/directive_registry.rb +259 -69
- data/lib/masterview/directives/.metadata +16 -0
- data/lib/masterview/directives/attr.rb +9 -8
- data/lib/masterview/directives/block.rb +11 -14
- data/lib/masterview/directives/check_box.rb +13 -18
- data/lib/masterview/directives/collection_select.rb +15 -29
- data/lib/masterview/directives/content.rb +9 -3
- data/lib/masterview/directives/else.rb +15 -13
- data/lib/masterview/directives/elsif.rb +14 -13
- data/lib/masterview/directives/eval.rb +20 -0
- data/lib/masterview/directives/form.rb +56 -9
- data/lib/masterview/directives/form_remote.rb +26 -0
- data/lib/masterview/directives/global_inline_erb.rb +10 -14
- data/lib/masterview/directives/hidden_field.rb +11 -20
- data/lib/masterview/directives/if.rb +13 -12
- data/lib/masterview/directives/image_tag.rb +20 -28
- data/lib/masterview/directives/import.rb +5 -12
- data/lib/masterview/directives/import_render.rb +7 -19
- data/lib/masterview/directives/insert_generated_comment.rb +8 -11
- data/lib/masterview/directives/javascript_include.rb +21 -12
- data/lib/masterview/directives/link_to.rb +14 -8
- data/lib/masterview/directives/link_to_function.rb +22 -0
- data/lib/masterview/directives/link_to_if.rb +15 -13
- data/lib/masterview/directives/link_to_remote.rb +13 -8
- data/lib/masterview/directives/omit_tag.rb +32 -16
- data/lib/masterview/directives/password_field.rb +10 -22
- data/lib/masterview/directives/radio_button.rb +11 -22
- data/lib/masterview/directives/replace.rb +7 -8
- data/lib/masterview/directives/select.rb +11 -24
- data/lib/masterview/directives/stylesheet_link.rb +20 -12
- data/lib/masterview/directives/submit.rb +11 -5
- data/lib/masterview/directives/text_area.rb +10 -23
- data/lib/masterview/directives/text_field.rb +10 -22
- data/lib/masterview/exceptions.rb +21 -0
- data/lib/masterview/extras/app/controllers/masterview_controller.rb +102 -75
- data/lib/masterview/extras/app/views/layouts/masterview_admin.rhtml +24 -23
- data/lib/masterview/extras/app/views/layouts/masterview_admin_config.rhtml +81 -0
- data/lib/masterview/extras/app/views/masterview/admin/configuration.rhtml +5 -1
- data/lib/masterview/extras/app/views/masterview/admin/create.rhtml +2 -2
- data/lib/masterview/extras/app/views/masterview/admin/directives.rhtml +5 -0
- data/lib/masterview/extras/app/views/masterview/admin/features.rhtml +5 -79
- data/lib/masterview/extras/app/views/masterview/admin/interact.rhtml +5 -0
- data/lib/masterview/extras/app/views/masterview/admin/list.rhtml +3 -71
- data/lib/masterview/extras/init_mv_admin_pages.rb +42 -23
- data/lib/masterview/filter_helpers.rb +26 -0
- data/lib/masterview/initializer.rb +99 -53
- data/lib/masterview/io.rb +19 -15
- data/lib/masterview/keyword_expander.rb +7 -2
- data/lib/masterview/masterview_info.rb +229 -23
- data/lib/masterview/masterview_version.rb +2 -2
- data/lib/masterview/parser.rb +275 -105
- data/lib/masterview/parser_helpers.rb +54 -0
- data/lib/masterview/rails_ext/action_controller_erb_direct.rb +29 -0
- data/lib/masterview/rails_ext/action_controller_reparse_checking.rb +27 -0
- data/lib/masterview/{extras/init_rails_erb_mv_direct.rb → rails_ext/action_view_erb_direct.rb} +12 -59
- data/lib/masterview/template_spec.rb +3 -2
- data/lib/masterview.rb +21 -12
- data/lib/rexml/parsers/baseparser_with_doctype_fix.rb +473 -0
- data/lib/rexml/parsers/sax2parser_with_doctype_fix.rb +243 -0
- data/test/directive_test_helper.rb +135 -0
- data/test/fixtures/directives/id_check.rb +18 -0
- data/test/fixtures/directives/test_directive_events.rb +70 -0
- data/test/test_helper.rb +18 -5
- data/test/tmp/views/layouts/product.rhtml +10 -10
- data/test/tmp/views/product/_form.rhtml +4 -4
- data/test/tmp/views/product/_product.rhtml +3 -3
- data/test/tmp/views/product/destroy.rhtml +5 -5
- data/test/tmp/views/product/edit.rhtml +4 -4
- data/test/tmp/views/product/list.rhtml +3 -3
- data/test/tmp/views/product/new.rhtml +4 -4
- data/test/tmp/views/product/show.rhtml +2 -2
- data/test/unit/attr_string_parser_test.rb +105 -0
- data/test/unit/case_insensitive_hash_mod_test.rb +104 -0
- data/test/unit/config_settings_test.rb +13 -1
- data/test/unit/default_generate_mio_filter_test.rb +3 -3
- data/test/unit/deprecated_directive_base_test.rb +30 -0
- data/test/unit/directive_attr_test.rb +111 -35
- data/test/unit/directive_base_test.rb +520 -1
- data/test/unit/directive_block_test.rb +30 -22
- data/test/unit/directive_content_test.rb +24 -11
- data/test/unit/directive_else_test.rb +18 -15
- data/test/unit/directive_elsif_test.rb +17 -15
- data/test/unit/directive_form_remote_test.rb +59 -0
- data/test/unit/directive_form_test.rb +31 -39
- data/test/unit/directive_global_inline_erb_test.rb +28 -17
- data/test/unit/directive_grid_test_notready.rb +38 -0
- data/test/unit/directive_helpers_test.rb +39 -0
- data/test/unit/directive_hidden_field_test.rb +44 -29
- data/test/unit/directive_if_test.rb +10 -7
- data/test/unit/directive_image_tag_test.rb +69 -61
- data/test/unit/directive_import_render_test.rb +28 -38
- data/test/unit/directive_import_test.rb +16 -14
- data/test/unit/directive_insert_generated_comment_test.rb +32 -0
- data/test/unit/directive_javascript_include_test.rb +40 -43
- data/test/unit/directive_link_to_function_test.rb +40 -0
- data/test/unit/directive_link_to_if_test.rb +52 -12
- data/test/unit/directive_link_to_remote_test.rb +58 -0
- data/test/unit/directive_link_to_test.rb +46 -31
- data/test/unit/directive_load_path_test.rb +257 -0
- data/test/unit/directive_metadata_test.rb +313 -0
- data/test/unit/directive_omit_tag_test.rb +73 -21
- data/test/unit/directive_password_field_test.rb +44 -38
- data/test/unit/directive_registry_test.rb +44 -0
- data/test/unit/directive_replace_test.rb +28 -12
- data/test/unit/directive_stylesheet_link_test.rb +43 -36
- data/test/unit/directive_submit_test.rb +29 -30
- data/test/unit/directive_text_area_test.rb +40 -36
- data/test/unit/directive_text_field_test.rb +44 -38
- data/test/unit/example_directive_child_events_test.rb +41 -0
- data/test/unit/example_test.rb +31 -4
- data/test/unit/file_mio_test.rb +18 -13
- data/test/unit/filter_helpers_test.rb +10 -8
- data/test/unit/find_directive_parent_test.rb +174 -0
- data/test/unit/keyword_expander_test.rb +4 -2
- data/test/unit/mio_test.rb +18 -11
- data/test/unit/mtime_string_hash_mio_tree_test.rb +5 -1
- data/test/unit/parser_test.rb +41 -29
- data/test/unit/pathname_extensions_test.rb +1 -1
- data/test/unit/run_parser_test.rb +2 -2
- data/test/unit/simplified_directive_base_test.rb +256 -0
- data/test/unit/string_hash_mio_test.rb +5 -1
- data/test/unit/template_file_watcher_test.rb +2 -2
- data/test/unit/template_test.rb +221 -46
- metadata +86 -45
- data/lib/masterview/directives/testfilter.rb +0 -55
- data/lib/masterview/extras/init_rails_reparse_checking.rb +0 -62
@@ -2,48 +2,48 @@ module MasterView
|
|
2
2
|
|
3
3
|
# Namespace module for built-in directive implementations
|
4
4
|
# that are standard with the MasterView template engine.
|
5
|
-
#
|
5
|
+
#
|
6
6
|
module Directives
|
7
7
|
end
|
8
8
|
|
9
9
|
# Base class for directive implementations.
|
10
|
-
#
|
10
|
+
#
|
11
11
|
# The standard technique for implementing a directive
|
12
12
|
# is to subclass DirectiveBase. The builtin
|
13
13
|
# MasterView directives are implemented in
|
14
|
-
# module namespace MasterView::Directives
|
15
|
-
#
|
14
|
+
# module namespace MasterView::Directives and
|
15
|
+
# uses the mv: namespace in directive attribute markup.
|
16
|
+
#
|
17
|
+
# Custom directive implementations should be created
|
18
|
+
# in your own module namespace, according to what's
|
19
|
+
# appropriate for your application or component.
|
20
|
+
# By default, directive extensions will use the
|
21
|
+
# mvx: namespace to distinguish extensions from the
|
22
|
+
# builtin MasterView directives.
|
23
|
+
#
|
16
24
|
# If you create a directive implementation class
|
17
|
-
# elsewhere in the class hierarchy,
|
18
|
-
#
|
25
|
+
# elsewhere in the class hierarchy, you include the
|
26
|
+
# DirectiveMetadata mixin class. It is also is recommended
|
27
|
+
# that you include DirectiveHelpers and DirectiveDSL.
|
19
28
|
# If you do not include the PluginLoadTracking mixin,
|
20
29
|
# you will need to manually register your directive
|
21
30
|
# class using the MasterView.register_directive service.
|
22
31
|
# either the PluginLoadTracking mixin or
|
23
|
-
#
|
24
|
-
#
|
32
|
+
#
|
25
33
|
#--
|
26
34
|
#TODO: add docs here on responsibilities and techniques for
|
27
35
|
# implementing directives. Subclass DirectiveBase, define
|
28
36
|
# within MasterView::Directives module namespace.
|
29
|
-
#
|
30
|
-
# mumble - class methods:
|
31
|
-
# attr_name is the directive's attribute markup name - def. is class name
|
32
|
-
# full_attr_name(ns) is the qualified name (name-space prefixed)
|
33
|
-
#
|
34
|
-
# Directive can optionally implement class method :on_load to initialize
|
35
|
-
# itself prior to processed for the directive registry
|
36
|
-
#
|
37
|
-
#TODO: establish protocol convention for additional namespaces
|
38
37
|
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
#
|
44
|
-
#
|
38
|
+
# A directive can optionally implement class method :on_load to
|
39
|
+
# initialize itself prior to being added to the directive registry.
|
40
|
+
#
|
41
|
+
# Directives may specify a <code>priority</code> in their metadata
|
42
|
+
# to control the processing order when multiple directive attributes
|
43
|
+
# are used on a template document element.
|
44
|
+
#
|
45
45
|
#TODO: document the priority hierarchy and convention for level usage
|
46
|
-
#
|
46
|
+
#
|
47
47
|
# Discuss operational context: describe how/when MasterView parser
|
48
48
|
# invokes a directive handler in the course of parsing the elements
|
49
49
|
# and attributes of a template document node hierarchy.
|
@@ -51,25 +51,20 @@ module MasterView
|
|
51
51
|
# information is available to a directive when invoked;
|
52
52
|
# what services are available in order to produce some effect
|
53
53
|
# on the results of the template parse.
|
54
|
-
#
|
54
|
+
#
|
55
55
|
# Two general flavors on content directives: those which operate on attribute
|
56
56
|
# values of the containing element and those which operate on the
|
57
57
|
# entire containing element, sometimes by supplying or modifying its
|
58
58
|
# content, in other cases by replacing the template element with something
|
59
|
-
# else.
|
60
|
-
#
|
59
|
+
# else.
|
60
|
+
#
|
61
61
|
# Third flavor: eval-only directive. Expression which is evaluate for its
|
62
62
|
# effect on the directive processing context or the overall state of processing
|
63
63
|
# the template document element tree.
|
64
|
-
#
|
65
|
-
# Directive implementation typically wants to implement either or both of
|
66
|
-
# the methods <code>stag(dcs)</code> and <code>etag(dcs)</code> to hook
|
67
|
-
# up its processing on the start/end tags of the element on which the
|
68
|
-
# attribute is defined.
|
69
|
-
#
|
64
|
+
#
|
70
65
|
# When a directive attribute is used on a template document element,
|
71
66
|
# the directive class is instantiated with the attribute_value provided
|
72
|
-
# to its constructure. All directives used on an element are sorted
|
67
|
+
# to its constructure. All directives used on an element are sorted
|
73
68
|
# into processing order according to their <code>priority</code>
|
74
69
|
# (default is <code>Medium</code>. The directive processor is invoked
|
75
70
|
# when the element start tag is encountered and when the element end
|
@@ -77,58 +72,25 @@ module MasterView
|
|
77
72
|
# how its processing is hooked up to effect the template output.
|
78
73
|
#++
|
79
74
|
#
|
80
|
-
class
|
75
|
+
class DirectiveBase
|
81
76
|
include PluginLoadTracking
|
77
|
+
include DirectiveMetadata
|
82
78
|
include DirectiveHelpers
|
79
|
+
include DirectiveDSL
|
83
80
|
|
84
81
|
# Register a class manually without regard to whether it inherits from DirectiveBase.
|
85
82
|
# Classes which derive from DirectiveBase will automatically be registered as they are
|
86
83
|
# loaded.
|
87
84
|
def self.register_directive(directive_class)
|
88
|
-
#ISSUE: do we really need both PluginLoadTracking.register_class
|
85
|
+
#ISSUE: do we really need both PluginLoadTracking.register_class
|
89
86
|
#and DirectiveBase.register_directive, in addition to MasterView.register_directive???
|
90
87
|
#[DJL 04-Jul-2006]
|
91
88
|
MasterView.register_directive(directive_class)
|
92
89
|
end
|
93
90
|
|
94
|
-
#
|
95
|
-
# consisting of the directive namespace and the directive attribute name.
|
96
|
-
#
|
97
|
-
# The default MasterView namespace_prefix is used if the directive does not
|
98
|
-
# specify a separate namespace.
|
99
|
-
#
|
100
|
-
#--
|
101
|
-
#TODO: clarify the mechanism by which alternate namespaces are defined.
|
102
|
-
# Is this done by a code value or configured as part of the directory
|
103
|
-
# path specifications, or some combination thereof to allow ovverides
|
104
|
-
# in the event of namespace collisions?
|
105
|
-
#++
|
106
|
-
#
|
107
|
-
def self.full_attr_name( namespace_prefix )
|
108
|
-
#TODO: fix this so that directives can override to define their own namespace separate from mv:
|
109
|
-
namespace_prefix + self.attr_name
|
110
|
-
end
|
111
|
-
|
112
|
-
# Returns the attribute name of the directive.
|
113
|
-
#
|
114
|
-
# Use full_attr_name to obtain the fully-qualified name
|
115
|
-
# of the directive attribute with the qualifying namespace prefix.
|
116
|
-
#
|
117
|
-
# The default attribute name of a directive is formed
|
118
|
-
# from the simple class name (without any module prefix qualifier),
|
119
|
-
# with the first character downcased.
|
120
|
-
#
|
121
|
-
def self.attr_name()
|
122
|
-
self.default_attr_name()
|
123
|
-
end
|
124
|
-
|
125
|
-
def self.default_attr_name() #:nodoc:
|
126
|
-
self.name.split(':').last.downcase_first_letter
|
127
|
-
end
|
128
|
-
|
129
|
-
# Construct a directive processor for the attribute_value
|
91
|
+
# Construct a directive processor with the attribute_value
|
130
92
|
# of a directive attribute on a document template element.
|
131
|
-
#
|
93
|
+
#
|
132
94
|
def initialize(attribute_value)
|
133
95
|
@attribute_value = attribute_value
|
134
96
|
end
|
@@ -145,88 +107,39 @@ module MasterView
|
|
145
107
|
|
146
108
|
# Set the directive's attribute value string to be processed.
|
147
109
|
def attr_value=(attribute_value)
|
110
|
+
#ISSUE: is this useful/necessary? Believe we only want initialzer to set this [DJL 23-Sep-2006]
|
148
111
|
@attribute_value = attribute_value
|
149
112
|
end
|
150
113
|
|
151
|
-
#
|
152
|
-
|
114
|
+
# Returns the attributes hash containing the attributes
|
115
|
+
# defined on the template document element that is being processed.
|
116
|
+
def element_attrs
|
153
117
|
@directive_call_stack.context[:tag].attributes
|
154
118
|
end
|
155
119
|
|
156
|
-
#
|
157
|
-
|
120
|
+
# Set the attributes hash containing the attributes
|
121
|
+
# for the template document element that is being processed.
|
122
|
+
def element_attrs=(attributes)
|
158
123
|
@directive_call_stack.context[:tag].attributes = attributes
|
159
124
|
end
|
160
125
|
|
161
|
-
#
|
162
|
-
def
|
163
|
-
@attrs_lckv ||= lowercase_attribute_keys_and_values(attrs)
|
164
|
-
end
|
165
|
-
|
166
|
-
#get attribute hash with lowercased keys (and original values) and cache it
|
167
|
-
def attrs_lck
|
168
|
-
@attrs_lck ||= lowercase_attribute_keys(attrs)
|
169
|
-
end
|
170
|
-
|
171
|
-
#returns true if the value for lckey of the attribute hash with lowercased keys and values
|
172
|
-
#matches (lowercase) lcmatch string
|
173
|
-
def attr_lckv_matches(lckey, lcmatch)
|
174
|
-
(attrs_lckv[lckey] && attrs_lckv[lckey] == lcmatch.downcase) ? true : false
|
175
|
-
end
|
176
|
-
|
177
|
-
#DEPRECATED - going away
|
178
|
-
#output '<% '+str+' %>'
|
179
|
-
def erb(str) #:nodoc:
|
180
|
-
#ISSUE: convert clients to erb_eval and drop. Ya oughta have a point of view. [DJL 04-Jul-2006]
|
181
|
-
ERB_START + str + ERB_END
|
182
|
-
end
|
183
|
-
|
184
|
-
# Compose an Erb expression which produces content in the containing document.
|
185
|
-
# The expression may also have effects on the processing context of
|
186
|
-
# the template document
|
187
|
-
#
|
188
|
-
# output '<%= '+str+' %>
|
189
|
-
#
|
190
|
-
def erb_content(str)
|
191
|
-
ERB_CONTENT_START + str + ERB_CONTENT_END
|
192
|
-
end
|
193
|
-
|
194
|
-
# Compose an Erb expression which is evaluated for its effect on the processing context
|
195
|
-
# but does not produce content in the containing document.
|
196
|
-
#
|
197
|
-
# output '<% '+str+' %>'
|
198
|
-
#
|
199
|
-
def erb_eval(str)
|
200
|
-
ERB_EVAL_START + str + ERB_EVAL_END
|
201
|
-
end
|
202
|
-
|
203
|
-
#get tag_name
|
204
|
-
def tag_name
|
126
|
+
# Returns the tag of the template document element that is being processed.
|
127
|
+
def element_tag
|
205
128
|
@directive_call_stack.context[:tag].tag_name
|
206
129
|
end
|
207
130
|
|
208
|
-
#
|
209
|
-
def
|
131
|
+
# Set the tag of the template document element that is being processed.
|
132
|
+
def element_tag=(tag_name)
|
210
133
|
@directive_call_stack.context[:tag].tag_name = tag_name
|
211
134
|
end
|
212
135
|
|
213
|
-
#inside characters, cdata, or comment you can call this to get the characters passed
|
214
|
-
def data
|
215
|
-
@directive_call_stack.context[:content_part]
|
216
|
-
end
|
217
|
-
|
218
|
-
#set the data that will be passed to characters, cdata, or comment directives
|
219
|
-
def data=(data)
|
220
|
-
@directive_call_stack.context[:content_part]=data
|
221
|
-
end
|
222
|
-
|
223
136
|
# rolled up content from all children of the tag, note this will not be complete until hitting the end tag method :etag
|
224
|
-
def
|
137
|
+
def content_array
|
225
138
|
@directive_call_stack.context[:tag].content
|
226
139
|
end
|
227
140
|
|
228
141
|
#return rolled up content from all children as string, note this will not be complete until hitting the end tag method :etag
|
229
|
-
def
|
142
|
+
def content_string
|
230
143
|
content = @directive_call_stack.context[:tag].content
|
231
144
|
content = content.join if content.respond_to? :join
|
232
145
|
content
|
@@ -237,63 +150,172 @@ module MasterView
|
|
237
150
|
@directive_call_stack.context[:tag].content = content
|
238
151
|
end
|
239
152
|
|
240
|
-
#
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
#
|
246
|
-
#
|
247
|
-
#
|
248
|
-
|
249
|
-
|
153
|
+
# Compose an Erb expression which produces content in the containing document.
|
154
|
+
# The expression may also have effects on the processing context of
|
155
|
+
# the template document.
|
156
|
+
#
|
157
|
+
# Enhanced allowing args to be passed in. If args are present then they will
|
158
|
+
# be assumed to be parameters for the method. A space will be appended to str
|
159
|
+
# and each argument will be appended joined with commas. Additionally if
|
160
|
+
# argument is a symbol then it will check for the existence of an instance variable
|
161
|
+
# with that name and if so substitutes its value. If any non-nil values are
|
162
|
+
# passed after it, then it will use its :default if that was specified
|
163
|
+
# in arg call, otherwise simply nil.
|
164
|
+
#
|
165
|
+
# output '<%= '+str+' %>
|
166
|
+
#
|
167
|
+
# erb_content(content, :a, :b, :c) where @a = 1, @b = nil (with optional_default of {}) and @c = {:hello => :world}
|
168
|
+
# becomes '<%= '+content+' 1, {}, {:hello => :world}'+' %>
|
169
|
+
#
|
170
|
+
def erb_content(str, *args)
|
171
|
+
ERB_CONTENT_START + prepare_output(str,*args) + ERB_CONTENT_END
|
250
172
|
end
|
251
173
|
|
252
|
-
|
253
|
-
|
174
|
+
# Compose an Erb expression which is evaluated for its effect on the processing context
|
175
|
+
# but does not produce content in the containing document.
|
176
|
+
#
|
177
|
+
# Enhanced allowing args to be passed in. If args are present then they will
|
178
|
+
# be assumed to be parameters for the method. A space will be appended to str
|
179
|
+
# and each argument will be appended joined with commas. Additionally if
|
180
|
+
# argument is a symbol then it will check for the existence of an instance variable
|
181
|
+
# with that name and if so substitutes its value. If any non-nil values are
|
182
|
+
# passed after it, then it will use its :default if that was specified
|
183
|
+
# in arg call, otherwise simply nil.
|
184
|
+
#
|
185
|
+
# output '<% '+str+' %>
|
186
|
+
#
|
187
|
+
# erb_eval(str, :a, :b, :c) where @a = 1, @b = nil (with optional_default of {}) and @c = {:hello => :world}
|
188
|
+
# becomes '<% '+str+' 1, {}, {:hello => :world}'+' %>
|
189
|
+
#
|
190
|
+
def erb_eval(str, *args)
|
191
|
+
ERB_EVAL_START + prepare_output(str,*args) + ERB_EVAL_END
|
254
192
|
end
|
255
193
|
|
256
|
-
#
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
194
|
+
# convert arg symbols to instance_variable values if exist
|
195
|
+
# Enhanced allowing args to be passed in. If args are present then they will
|
196
|
+
# be assumed to be parameters for the method. A space will be appended to str
|
197
|
+
# and each argument will be appended joined with commas. Additionally if
|
198
|
+
# argument is a symbol then it will check for the existence of an instance variable
|
199
|
+
# with that name and if so substitutes its value. If any non-nil values are
|
200
|
+
# passed after it, then it will use its :default if that was specified
|
201
|
+
# in arg call, otherwise simply nil.
|
202
|
+
#
|
203
|
+
# output '<%= '+str+' %>
|
204
|
+
#
|
205
|
+
# prepare_output(content, :a, :b, :c) where @a = 1, @b = nil (with optional_default of {}) and @c = {:hello => :world}
|
206
|
+
# becomes '<%= '+content+' 1, {}, {:hello => :world}'+' %>
|
207
|
+
#
|
208
|
+
# returns string of output
|
209
|
+
def prepare_output(str, *args)
|
210
|
+
out = str
|
211
|
+
non_nil_found = false
|
212
|
+
arg_values = []
|
213
|
+
args.reverse_each do |arg|
|
214
|
+
value = nil
|
215
|
+
invar_name = name_to_instance_var_name(arg)
|
216
|
+
var_sym_name = (invar_name.to_s.starts_with?('@')) ? invar_name.to_s[1..-1].to_sym : invar_name
|
217
|
+
attr_arg_def = self.class.directive_class_def.find_attr_arg_def_by_name(var_sym_name)
|
218
|
+
if instance_variable_exists?(invar_name)
|
219
|
+
value = self.instance_variable_get(invar_name)
|
220
|
+
else # symbol instance variable not found, assume need to use literal arg value
|
221
|
+
value = arg
|
222
|
+
end
|
223
|
+
if attr_arg_def and attr_arg_def.options and attr_arg_def.options[:varargs] # arg contains array of values that need to be expanded
|
224
|
+
if value.nil? or value.empty?
|
225
|
+
value = nil
|
226
|
+
else
|
227
|
+
value = value.join(', ') # expand these values out to foo, bar, baz
|
228
|
+
end
|
229
|
+
end
|
230
|
+
if non_nil_found # insure that the preceding values are specified
|
231
|
+
if value.nil?
|
232
|
+
value = attr_arg_def.optional_default unless attr_arg_def.nil? #try to use optional_default if exists
|
233
|
+
end
|
234
|
+
|
235
|
+
value = 'nil' if value.nil? or (value.is_a?(String) and value.strip.empty?) # finally we will be outputing the string word nil if value is still nil
|
236
|
+
if(value.is_a?(String))
|
237
|
+
value = '{ '+value+' }' if value =~ /^[^\{]+=>/
|
238
|
+
end
|
239
|
+
else # no non_nil_found previously, check this one
|
240
|
+
value = nil if value.is_a?(String) and value.strip.empty?
|
241
|
+
non_nil_found = true unless value.nil?
|
242
|
+
end
|
243
|
+
unless value.nil?
|
244
|
+
value = value.inspect unless value.is_a?(String) # insure is string inspect works for many things
|
245
|
+
arg_values.unshift(value) # if values are non-nil at this point add them to arg_values (to end first)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
out = out + '( ' + arg_values.join(', ') + ' )' unless arg_values.empty?
|
249
|
+
out
|
262
250
|
end
|
263
251
|
|
264
|
-
#
|
265
|
-
def
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
252
|
+
# check for common html options and return the hash
|
253
|
+
def common_html_options
|
254
|
+
options = {}
|
255
|
+
if (v = element_attrs[:id]) : options[:id] = v; end
|
256
|
+
if (v = element_attrs[:class]) : options[:class] = v; end
|
257
|
+
if (v = element_attrs[:style]) : options[:style] = v; end
|
258
|
+
if (v = element_attrs[:tabindex]) : options[:tabindex] = v; end
|
259
|
+
if (v = element_attrs[:accesskey]) : options[:accesskey] = v; end
|
260
|
+
if (element_attrs[:disabled]) : options[:disabled] = true; end
|
261
|
+
if (element_attrs[:readonly]) : options[:readonly] = true; end
|
262
|
+
|
263
|
+
# these are not as common but take care of them anyway for convenience
|
264
|
+
if (v = element_attrs[:alt]) : options[:alt] = v; end
|
265
|
+
if (v = element_attrs[:width]) : options[:width] = v.to_i; end
|
266
|
+
if (v = element_attrs[:height]) : options[:height] = v.to_i; end
|
267
|
+
if (v = element_attrs[:rows]) : options[:rows] = v.to_i; end
|
268
|
+
if (v = element_attrs[:cols]) : options[:cols] = v.to_i; end
|
269
|
+
if (v = element_attrs[:size]) : options[:size] = v.to_i; end
|
270
|
+
if (v = element_attrs[:maxlength]) : options[:maxlength] = v.to_i; end
|
271
|
+
options
|
271
272
|
end
|
272
273
|
|
273
|
-
#merge
|
274
|
-
#
|
275
|
-
|
276
|
-
|
274
|
+
# merge a hash into a string representation of a hash,
|
275
|
+
# this method basically appends the hash values to the end of the
|
276
|
+
# string taking into account whether the hash has brackets or is
|
277
|
+
# open. When ruby reads a hash it will keep the last value set
|
278
|
+
# so later values override previous values
|
279
|
+
def merge_hash_into_str(hash_to_merge, str_to_merge_into)
|
280
|
+
str_to_merge_into = '' if str_to_merge_into.nil?
|
281
|
+
sorted_hash_to_merge = hash_to_merge.sort { |a,b| a[0].to_s <=> b[0].to_s } #sort, remember the keys might be symbols so use to_s
|
282
|
+
str_to_merge = sorted_hash_to_merge.collect{ |h,v| "#{h.inspect} => #{v.inspect}" }.join(', ')
|
283
|
+
str = str_to_merge_into.strip
|
284
|
+
if(str[0,1] == '{') # has {} surrounding
|
285
|
+
str = str[1..-2].strip # get just contents stripping {}
|
286
|
+
str += ', ' unless str.empty? or str_to_merge.empty?
|
287
|
+
str += str_to_merge
|
288
|
+
str = '{'+str+'}'
|
289
|
+
else
|
290
|
+
str += ', ' unless str.empty? or str_to_merge.empty?
|
291
|
+
str += str_to_merge
|
292
|
+
end
|
293
|
+
str
|
277
294
|
end
|
278
295
|
|
279
|
-
#
|
280
|
-
|
281
|
-
|
296
|
+
# find the first parent directive instance that matches the parentClass and if block is provided
|
297
|
+
# then evaluate the block as well allowing further filtering, if block is false then
|
298
|
+
# it won't be used as a match.
|
299
|
+
# This method is especially useful for providing a mechanism for children to locate
|
300
|
+
# parent directives and communicate with them potentially influencing their output.
|
301
|
+
# Once a parent directive instance is found, public methods on the parent directive
|
302
|
+
# can be called, so the child might add itself to some list, etc.
|
303
|
+
def find_parent_directive(parentClass, &block)
|
304
|
+
parent_dir = nil
|
305
|
+
tag = @directive_call_stack.context[:tag]
|
306
|
+
while( parent_dir.nil? )
|
307
|
+
tag = tag.parent
|
308
|
+
break if tag.nil?
|
309
|
+
parent_dir = tag.directives.directives.find { |d| d.is_a?(parentClass) and (block.nil? or block.call(d)) }
|
310
|
+
end
|
311
|
+
parent_dir
|
282
312
|
end
|
283
313
|
|
284
|
-
#
|
285
|
-
def
|
286
|
-
|
287
|
-
options[:id] = attrs_lck['id'] if attrs_lck['id']
|
288
|
-
options[:class] = attrs_lck['class'] if attrs_lck['class']
|
289
|
-
options[:style] = attrs_lck['style'] if attrs_lck['style']
|
290
|
-
options[:tabindex] = attrs_lck['tabindex'] if attrs_lck['tabindex']
|
291
|
-
options[:accesskey] = attrs_lck['accesskey'] if attrs_lck['accesskey']
|
292
|
-
options[:disabled] = true if attrs_lck['disabled']
|
293
|
-
options[:readonly] = true if attrs_lck['readonly']
|
294
|
-
options
|
314
|
+
# convenience method to get to current renderer
|
315
|
+
def renderer
|
316
|
+
@directive_call_stack.context[:tag].renderer
|
295
317
|
end
|
296
318
|
|
297
319
|
end
|
298
|
-
|
299
320
|
end
|
321
|
+
|