dryml 1.1.0.pre0

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.
@@ -0,0 +1,187 @@
1
+ module Dryml
2
+
3
+ class TemplateHandler < ActionView::TemplateHandler
4
+
5
+ def compile(*args)
6
+ # Ignore - we handle compilation ourselves
7
+ end
8
+
9
+ # Pre Rails 2.2
10
+ def render(template)
11
+ renderer = Dryml.page_renderer_for_template(@view, template.locals.keys, template)
12
+ this = @view.instance_variable_set("@this", @view.controller.send(:dryml_context) || template.locals[:this])
13
+ s = renderer.render_page(this, template.locals)
14
+ # Important to strip whitespace, or the browser hangs around for ages (FF2)
15
+ s.strip
16
+ end
17
+
18
+ def render_for_rails22(template, view, local_assigns)
19
+ renderer = Dryml.page_renderer_for_template(view, local_assigns.keys, template)
20
+ this = view.controller.send(:dryml_context) || local_assigns[:this]
21
+ @view._?.instance_variable_set("@this", this)
22
+ s = renderer.render_page(this, local_assigns)
23
+
24
+ # Important to strip whitespace, or the browser hangs around for ages (FF2)
25
+ s.strip
26
+ end
27
+
28
+ end
29
+
30
+ end
31
+
32
+ module ActionController
33
+
34
+ class Base
35
+
36
+ def dryml_context
37
+ @this
38
+ end
39
+
40
+ def dryml_fallback_tag(tag_name)
41
+ @dryml_fallback_tag = tag_name
42
+ end
43
+
44
+
45
+ def call_dryml_tag(tag, options={})
46
+ @template.send(:_evaluate_assigns_and_ivars)
47
+
48
+ # TODO: Figure out what this bit is all about :-)
49
+ if options[:with]
50
+ @this = options[:with] unless options[:field]
51
+ else
52
+ options[:with] = dryml_context
53
+ end
54
+
55
+ Dryml.render_tag(@template, tag, options)
56
+ end
57
+
58
+
59
+ # TODO: This is namespace polution, should be called render_dryml_tag
60
+ def render_tag(tag, attributes={}, options={})
61
+ text = call_dryml_tag(tag, attributes)
62
+ text && render({:text => text, :layout => false }.merge(options))
63
+ end
64
+
65
+ # DRYML fallback tags -- monkey patch this method to attempt to render a tag if there's no template
66
+ def render_for_file_with_dryml(template, status = nil, layout = nil, locals = {})
67
+ # in rails 2.2, "template" is actually "template_path"
68
+
69
+ # if we're passed a MissingTemplateWrapper, see if there's a
70
+ # dryml tag that will render the page
71
+ if template.respond_to? :original_template_path
72
+ # this is the Rails 2.3 path
73
+ tag_name = @dryml_fallback_tag || "#{File.basename(template.original_template_path).dasherize}-page"
74
+
75
+ text = call_dryml_tag(tag_name)
76
+ if text
77
+ return render_for_text(text, status)
78
+ else
79
+ template.raise_wrapped_exception
80
+ end
81
+ else
82
+ begin
83
+ result = render_for_file_without_dryml(template, status, layout, locals)
84
+ rescue ActionView::MissingTemplate => ex
85
+ # this is the Rails 2.2 path
86
+ tag_name = @dryml_fallback_tag || "#{File.basename(template).dasherize}-page"
87
+
88
+ text = call_dryml_tag(tag_name)
89
+ if text
90
+ return render_for_text(text, status)
91
+ else
92
+ raise ex
93
+ end
94
+ end
95
+ end
96
+ end
97
+ alias_method_chain :render_for_file, :dryml
98
+
99
+ end
100
+ end
101
+
102
+ class ActionView::Template
103
+
104
+ def render_with_dryml(view, local_assigns = {})
105
+ if handler == Dryml::TemplateHandler
106
+ render_dryml(view, local_assigns)
107
+ else
108
+ render_without_dryml(view, local_assigns)
109
+ end
110
+ end
111
+ alias_method_chain :render, :dryml
112
+
113
+ # We've had to copy a bunch of logic from Renderable#render, because we need to prevent Rails
114
+ # from trying to compile our template. DRYML templates are each compiled as a class, not just a method,
115
+ # so the support for compiling templates that Rails provides is innadequate.
116
+ def render_dryml(view, local_assigns = {})
117
+ if view.instance_variable_defined?(:@_render_stack)
118
+ # Rails 2.2
119
+ stack = view.instance_variable_get(:@_render_stack)
120
+ stack.push(self)
121
+
122
+ # This is only used for TestResponse to set rendered_template
123
+ unless is_a?(ActionView::InlineTemplate) || view.instance_variable_get(:@_first_render)
124
+ view.instance_variable_set(:@_first_render, self)
125
+ end
126
+
127
+ view.send(:_evaluate_assigns_and_ivars)
128
+ view.send(:_set_controller_content_type, mime_type) if respond_to?(:mime_type)
129
+
130
+ result = Dryml::TemplateHandler.new.render_for_rails22(self, view, local_assigns)
131
+
132
+ stack.pop
133
+ result
134
+ else
135
+ # Rails 2.3
136
+ compile(local_assigns)
137
+
138
+ view.with_template self do
139
+ view.send(:_evaluate_assigns_and_ivars)
140
+ view.send(:_set_controller_content_type, mime_type) if respond_to?(:mime_type)
141
+
142
+ Dryml::TemplateHandler.new.render_for_rails22(self, view, local_assigns)
143
+ end
144
+ end
145
+ end
146
+
147
+ end
148
+
149
+ # this is only used in Rails 2.3
150
+ class MissingTemplateWrapper
151
+ attr_reader :original_template_path
152
+
153
+ def initialize(exception, path)
154
+ @exception = exception
155
+ @original_template_path = path
156
+ end
157
+
158
+ def method_missing(*args)
159
+ raise @exception
160
+ end
161
+
162
+ def render
163
+ raise @exception
164
+ end
165
+ end
166
+
167
+
168
+ module ActionView
169
+ class PathSet < Array
170
+ # this is only used by Rails 2.3
171
+ def find_template_with_dryml(original_template_path, format = nil, html_fallback = true)
172
+ begin
173
+ find_template_without_dryml(original_template_path, format, html_fallback)
174
+ rescue ActionView::MissingTemplate => ex
175
+ # instead of throwing the exception right away, hand back a
176
+ # time bomb instead. It'll blow if mishandled...
177
+ return MissingTemplateWrapper.new(ex, original_template_path)
178
+ end
179
+ end
180
+
181
+ if method_defined? "find_template"
182
+ # only rails 2.3 has this function
183
+ alias_method_chain :find_template, :dryml
184
+ end
185
+ end
186
+ end
187
+
data/lib/dryml.rb ADDED
@@ -0,0 +1,291 @@
1
+ # The Don't Repeat Yourself Markup Language
2
+ #
3
+ # Author:: Tom Locke (tom@tomlocke.com)
4
+ # Copyright:: Copyright (c) 2008
5
+ # License:: Distributes under the same terms as Ruby
6
+
7
+
8
+
9
+ # gem dependencies
10
+ require 'hobosupport'
11
+ require 'action_pack'
12
+ require 'active_record' if ActionPack::VERSION::MAJOR==2 && ActionPack::VERSION::MINOR==2
13
+
14
+ ActiveSupport::Dependencies.load_paths |= [ File.dirname(__FILE__)] if ActiveSupport.const_defined? :Dependencies
15
+
16
+ # Hobo can be installed in /vendor/hobo, /vendor/plugins/hobo, vendor/plugins/hobo/hobo, etc.
17
+ ::DRYML_ROOT = File.expand_path(File.dirname(__FILE__) + "/..")
18
+
19
+ # The Don't Repeat Yourself Markup Language
20
+ module Dryml
21
+
22
+ VERSION = "1.1.0.pre0"
23
+
24
+ class DrymlSyntaxError < RuntimeError; end
25
+
26
+ class DrymlException < Exception
27
+ def initialize(message, path=nil, line_num=nil)
28
+ if path && line_num
29
+ super(message + " -- at #{path}:#{line_num}")
30
+ else
31
+ super(message)
32
+ end
33
+ end
34
+ end
35
+
36
+ TagDef = Struct.new "TagDef", :name, :attrs, :proc
37
+
38
+ RESERVED_WORDS = %w{if for while do class else elsif unless case when module in}
39
+
40
+ EMPTY_PAGE = "[tag-page]"
41
+
42
+ APPLICATION_TAGLIB = { :src => "taglibs/application" }
43
+ CORE_TAGLIB = { :src => "core", :plugin => "dryml" }
44
+
45
+ DEFAULT_IMPORTS = defined?(ApplicationHelper) ? [ApplicationHelper] : []
46
+
47
+ @renderer_classes = {}
48
+ @tag_page_renderer_classes = {}
49
+
50
+ extend self
51
+
52
+ attr_accessor :last_if
53
+
54
+ def enable(generator_directories=[], output_directory=".")
55
+ ActionView::Template.register_template_handler("dryml", Dryml::TemplateHandler)
56
+ if ActionView::Template.respond_to? :exempt_from_layout
57
+ ActionView::Template.exempt_from_layout('dryml')
58
+ elsif
59
+ ActionView::Base.exempt_from_layout('dryml')
60
+ end
61
+ DrymlGenerator.enable(generator_directories, output_directory)
62
+ end
63
+
64
+
65
+ def precompile_taglibs
66
+ Dir.chdir(RAILS_ROOT) do
67
+ taglibs = Dir["vendor/plugins/**/taglibs/**/*.dryml"] + Dir["app/views/taglibs/**/*.dryml"]
68
+ taglibs.each do |f|
69
+ Dryml::Taglib.get(:template_dir => File.dirname(f), :src => File.basename(f).remove(".dryml"))
70
+ end
71
+ end
72
+ end
73
+
74
+
75
+ def clear_cache
76
+ @renderer_classes = {}
77
+ @tag_page_renderer_classes = {}
78
+ end
79
+
80
+ def render_tag(view, tag, options={})
81
+ renderer = empty_page_renderer(view)
82
+ renderer.render_tag(tag, options)
83
+ end
84
+
85
+
86
+ def empty_page_renderer(view)
87
+ controller_name = view.controller.class.name.underscore.sub(/_controller$/, "")
88
+ page_renderer(view, [], "#{controller_name}/#{EMPTY_PAGE}")
89
+ end
90
+
91
+
92
+ def page_renderer_for_template(view, local_names, template)
93
+ page_renderer(view, local_names, template.path_without_extension, template.filename)
94
+ end
95
+
96
+
97
+ def page_renderer(view, local_names=[], page=nil, filename=nil)
98
+ if RAILS_ENV == "development"
99
+ clear_cache
100
+ Taglib.clear_cache
101
+ end
102
+
103
+ prepare_view!(view)
104
+ included_taglibs = ([APPLICATION_TAGLIB, subsite_taglib(page)] + controller_taglibs(view.controller.class)).compact
105
+
106
+ if page.ends_with?(EMPTY_PAGE)
107
+ # DELETE ME: controller_class = controller_class_for(page)
108
+ controller_class = view.controller.class
109
+ @tag_page_renderer_classes[controller_class.name] ||=
110
+ make_renderer_class("", page, local_names, DEFAULT_IMPORTS, included_taglibs)
111
+ @tag_page_renderer_classes[controller_class.name].new(page, view)
112
+ else
113
+ filename ||= if view.view_paths.respond_to? :find_template
114
+ # Rails 2.3
115
+ view.view_paths.find_template(page + ".dryml").filename
116
+ else
117
+ # Rails 2.2
118
+ view._pick_template(page + ".dryml").filename
119
+ end
120
+ mtime = File.mtime(filename)
121
+ renderer_class = @renderer_classes[page]
122
+
123
+ # do we need to recompile?
124
+ if (!renderer_class || # nothing cached?
125
+ (local_names - renderer_class.compiled_local_names).any? || # any new local names?
126
+ renderer_class.load_time < mtime) # cache out of date?
127
+ renderer_class = make_renderer_class(File.read(filename), filename, local_names,
128
+ DEFAULT_IMPORTS, included_taglibs)
129
+ renderer_class.load_time = mtime
130
+ @renderer_classes[page] = renderer_class
131
+ end
132
+ renderer_class.new(page, view)
133
+ end
134
+ end
135
+
136
+
137
+ # TODO: Delete this - not needed (use view.controller.class)
138
+ def controller_class_for(page)
139
+ controller, view = Controller.controller_and_view_for(page)
140
+ "#{controller.camelize}Controller".constantize
141
+ end
142
+
143
+
144
+ def controller_taglibs(controller_class)
145
+ controller_class.try.included_taglibs || []
146
+ end
147
+
148
+
149
+ def subsite_taglib(page)
150
+ parts = page.split("/")
151
+ subsite = parts.length >= 3 ? parts[0..-3].join('_') : "front"
152
+ src = "taglibs/#{subsite}_site"
153
+ { :src => src } if Object.const_defined?(:RAILS_ROOT) && File.exists?("#{RAILS_ROOT}/app/views/#{src}.dryml")
154
+ end
155
+
156
+ def get_field(object, field)
157
+ return nil if object.nil?
158
+ field_str = field.to_s
159
+ begin
160
+ return object.send(field_str)
161
+ rescue NoMethodError => ex
162
+ if field_str =~ /^\d+$/
163
+ return object[field.to_i]
164
+ else
165
+ return object[field]
166
+ end
167
+ end
168
+ end
169
+
170
+
171
+ def get_field_path(object, path)
172
+ path = if path.is_a? String
173
+ path.split('.')
174
+ else
175
+ Array(path)
176
+ end
177
+
178
+ parent = nil
179
+ path.each do |field|
180
+ return nil if object.nil?
181
+ parent = object
182
+ object = get_field(parent, field)
183
+ end
184
+ [parent, path.last, object]
185
+ end
186
+
187
+
188
+ def prepare_view!(view)
189
+ # Not sure why this isn't done for me...
190
+ # There's probably a button to press round here somewhere
191
+ for var in %w(@flash @cookies @action_name @_session @_request @request_origin
192
+ @template @request @ignore_missing_templates @_headers @variables_added
193
+ @_flash @response @template_class
194
+ @_cookies @before_filter_chain_aborted @url
195
+ @_response @template_root @headers @_params @params @session)
196
+ unless @view.instance_variables.include?(var)
197
+ view.instance_variable_set(var, view.controller.instance_variable_get(var))
198
+ end
199
+ end
200
+ end
201
+
202
+ # create and compile a renderer class (AKA Dryml::Template::Environment)
203
+ #
204
+ # template_src:: the DRYML source
205
+ # template_path:: the filename of the source. This is used for
206
+ # caching
207
+ # locals:: local variables.
208
+ # imports:: A list of helper modules to import. For example, Hobo
209
+ # uses [Hobo::HoboHelper, Hobo::Translations,
210
+ # ApplicationHelper]
211
+ # included_taglibs:: A list of Taglibs to include. { :src =>
212
+ # "core", :plugin => "dryml" } is automatically
213
+ # added to this list.
214
+ #
215
+ def make_renderer_class(template_src, template_path, locals=[], imports=[], included_taglibs=[])
216
+ renderer_class = Class.new(TemplateEnvironment)
217
+ compile_renderer_class(renderer_class, template_src, template_path, locals, imports, included_taglibs)
218
+ renderer_class
219
+ end
220
+
221
+
222
+ def compile_renderer_class(renderer_class, template_src, template_path, locals, imports, included_taglibs=[])
223
+ template = Dryml::Template.new(template_src, renderer_class, template_path)
224
+ imports.each {|m| template.import_module(m)}
225
+
226
+ taglibs = [CORE_TAGLIB] + included_taglibs
227
+
228
+ # the sum of all the names we've seen so far - eventually we'll be ready for all of 'em
229
+ all_local_names = renderer_class.compiled_local_names | locals
230
+
231
+ template.compile(all_local_names, taglibs)
232
+ end
233
+
234
+
235
+ def unreserve(word)
236
+ word = word.to_s
237
+ if RESERVED_WORDS.include?(word)
238
+ word + "_"
239
+ else
240
+ word
241
+ end
242
+ end
243
+
244
+
245
+ def static_tags
246
+ @static_tags ||= begin
247
+ path = if Object.const_defined?(:RAILS_ROOT) && FileTest.exists?("#{RAILS_ROOT}/config/dryml_static_tags.txt")
248
+ "#{RAILS_ROOT}/config/dryml_static_tags.txt"
249
+ else
250
+ File.join(File.dirname(__FILE__), "dryml/static_tags")
251
+ end
252
+ File.readlines(path).*.chop
253
+ end
254
+ end
255
+
256
+ attr_writer :static_tags
257
+
258
+ # Helper function for use outside Hobo/Rails
259
+ #
260
+ # Pass the template context in locals[:this]
261
+ #
262
+ # This function caches. If the mtime of template_path is older
263
+ # than the last compilation time, the cached version will be
264
+ # used. If no template_path is given, template_src is used as the
265
+ # key to the cache.
266
+ #
267
+ # If a local variable is not present when the template is
268
+ # compiled, it will be ignored when the template is used. In
269
+ # other words, the variable values may change, but the names may
270
+ # not.
271
+ #
272
+ # included_taglibs is only used during template compilation.
273
+ #
274
+ # @param [String] template_src the DRYML source
275
+ # @param [Hash] locals local variables.
276
+ # @param [String, nil] template_path the filename of the source.
277
+ # @param [Array] included_taglibs A list of Taglibs to include. { :src =>
278
+ # "core", :plugin => "dryml" } is automatically
279
+ # added to this list.
280
+ # @param [ActionView::Base] view an ActionView instance
281
+ def render(template_src, locals={}, template_path=nil, included_taglibs=[], view=nil)
282
+ template_path ||= template_src
283
+ view ||= ActionView::Base.new(ActionController::Base.view_paths, {})
284
+ this = locals.delete(:this) || nil
285
+
286
+ renderer_class = Dryml::Template.build_cache[template_path]._?.environment ||
287
+ Dryml.make_renderer_class(template_src, template_path, locals.keys)
288
+ renderer_class.new(template_path, view).render_page(this, locals)
289
+ end
290
+
291
+ end
@@ -0,0 +1,136 @@
1
+ <!-- Core DRYML tags. These are included implicitly and are always available. Contains mainly control-flow tags. -->
2
+
3
+ <!-- Call the tag given by the `tag` attribute. This lets you call tags dynamically based on some runtime value.
4
+ It's the DRYML equivalent of Ruby's `send` method.
5
+ -->
6
+ <def tag="call-tag" attrs="tag">
7
+ <%= send(tag.gsub('-', '_'), attributes, parameters) %>
8
+ </def>
9
+
10
+
11
+ <!-- Wrap the body in the tag specified by the `tag` attribute, iff `when` is true.
12
+
13
+ Using regular DRYML conditional logic it is rather akward to conditionally wrap some tag in another tag. This tag makes it easy to do that.
14
+
15
+ ### Usage
16
+
17
+ For example, you might want to wrap an `<img>` tag in an `<a>` tag but only under certain conditions. Say the current context has an `href` attribute that may or may not be nil. We want to wrap the img in `<a>` if `href` is not nil:
18
+
19
+ <wrap when="&this.href.present?" tag="a" href="&this.href"><img src="&this.img_filename"/></wrap>
20
+ {: .dryml}
21
+ -->
22
+ <def tag="wrap" attrs="tag, when, parameter">
23
+ <% parameter ||= :default %>
24
+ <%= when_ ? send(tag, attributes, { parameter.to_sym => parameters[:default] }) : parameters.default %>
25
+ </def>
26
+
27
+
28
+ <!-- DRYML version of `render(:partial => 'my_partial')`
29
+
30
+ ### Usage
31
+
32
+ <partial name="my-partial" locals="&{:x => 10, :y => 20}"/>
33
+ -->
34
+ <def tag="partial" attrs="name, locals"><%=
35
+ locals ||= {}
36
+ render(:partial => name, :locals => locals.merge(:this => this))
37
+ %></def>
38
+
39
+
40
+ <!-- Repeat a section of mark-up. The context should be a collection (anything that responds to `each`). The content of the call to `<repeat>` will be repeated for each item in the collection, and the context will be set to each item in turn.
41
+
42
+ ### Attributes
43
+
44
+ - join: The value of this attribute, if given, will be inserted between each of the items (e.g. `join=", "` is very common).
45
+ -->
46
+ <def tag="repeat" attrs="join"><if><%=
47
+ raise ArgumentError, "Cannot <repeat> on #{this.inspect}" unless this.respond_to? :each
48
+ context_map do
49
+ parameters.default
50
+ end.join(join)
51
+ %></if></def>
52
+
53
+
54
+ <!-- The 'do nothing' tag. Used to add parameters or change context without adding any markup -->
55
+ <def tag="do"><%= parameters.default %></def>
56
+
57
+ <!-- Alias of `do` -->
58
+ <def tag="with" alias-of="do"/>
59
+
60
+ <!-- DRYML's 'if' test
61
+
62
+ ### Usage
63
+
64
+ <if test="&current_user.administrtator?">Logged in as administrator</if>
65
+ <else>Logged in as normal user</else>
66
+
67
+ **IMPORTANT NOTE**: `<if>` tests for non-blank vs. blank (as defined by ActiveSuport), not true vs. false.
68
+
69
+ If you do not give the `test` attribute, uses the current context instead. This allows a nice trick like this:
70
+
71
+ <if:comments>...</if>
72
+
73
+ This has the double effect of changing the context to the `this.comments`, and only evaluating the body if there are comments (because an empty
74
+ collection is considered blank)
75
+ -->
76
+ <def tag="if" attrs="test"><%=
77
+ test = all_attributes.fetch(:test, this)
78
+ res = (cond = !test.blank?) ? parameters.default : ""
79
+ Dryml.last_if = cond
80
+ res
81
+ %></def>
82
+
83
+ <!-- General purpose `else` clause.
84
+
85
+ `<else>` works with various tags such as `<if>` and `<repeat>` (the else clause will be output if the collection was empty). It simply outputs its content if `Dryml.last_if` is false. This is pretty much a crazy hack which violates many good principles of language design, but it's very useful : )
86
+ -->
87
+ <def tag="else"><%= parameters.default unless Dryml.last_if %></def>
88
+
89
+
90
+ <!-- Same behaviour as `<if>`, except the test is negated. -->
91
+ <def tag="unless" attrs="test"><%=
92
+ test = all_attributes.fetch(:test, this)
93
+ res = (cond = test.blank?) ? parameters.default : ""
94
+ Dryml.last_if = cond
95
+ res
96
+ %></def>
97
+
98
+
99
+ <!-- nodoc. -->
100
+ <def tag="fake-field-context" attrs="fake-field, context"><%=
101
+ res = ""
102
+ new_field_context(fake_field, context) { res << parameters.default }
103
+ res
104
+ %></def>
105
+
106
+
107
+ <!-- nodoc. Define core HTML tags defined in Rapid so that DRYML can be used without Rapid. -->
108
+ <def tag="html"><%= "<html#{tag_options(attributes)}>" -%><do param="default"/><%= "</html>" -%></def>
109
+
110
+ <!-- nodoc. Define core HTML tags defined in Rapid so that DRYML can be used without Rapid. -->
111
+ <def tag="table"><%= "<table#{tag_options(attributes)}>" -%><do param="default"/><%= "</table>" -%></def>
112
+
113
+ <!-- nodoc. Define core HTML tags defined in Rapid so that DRYML can be used without Rapid. -->
114
+ <def tag="a"><%= "<a#{tag_options(attributes)}>" -%><do param="default"/><%= "</a>" -%></def>
115
+
116
+ <!-- nodoc. Define core HTML tags defined in Rapid so that DRYML can be used without Rapid. -->
117
+ <def tag="section"><%= "<section#{tag_options(attributes)}>" -%><do param="default"/><%= "</section>" -%></def>
118
+
119
+ <!-- nodoc. Define core HTML tags defined in Rapid so that DRYML can be used without Rapid. -->
120
+ <def tag="header"><%= "<header#{tag_options(attributes)}>" -%><do param="default"/><%= "</header>" -%></def>
121
+
122
+ <!-- nodoc. Define core HTML tags defined in Rapid so that DRYML can be used without Rapid. -->
123
+ <def tag="footer"><%= "<footer#{tag_options(attributes)}>" -%><do param="default"/><%= "</footer>" -%></def>
124
+
125
+ <!-- nodoc. Define core HTML tags defined in Rapid so that DRYML can be used without Rapid. -->
126
+ <def tag="form"><%= "<form#{tag_options(attributes)}>" -%><do param="default"/><%= "</form>" -%></def>
127
+
128
+ <!-- nodoc. Define core HTML tags defined in Rapid so that DRYML can be used without Rapid. -->
129
+ <def tag="submit"><%= "<submit#{tag_options(attributes)}>" -%><do param="default"/><%= "</submit>" -%></def>
130
+
131
+ <!-- nodoc. Define core HTML tags defined in Rapid so that DRYML can be used without Rapid. -->
132
+ <def tag="input"><%= "<input#{tag_options(attributes)}>" -%><do param="default"/><%= "</input>" -%></def>
133
+
134
+ <!-- nodoc. Define core HTML tags defined in Rapid so that DRYML can be used without Rapid. -->
135
+ <def tag="link"><%= "<link#{tag_options(attributes)}>" -%><do param="default"/><%= "</link>" -%></def>
136
+
@@ -0,0 +1,68 @@
1
+
2
+ >> require 'rubygems'
3
+ >> require 'active_support'
4
+ >> require 'action_view'
5
+ >> require 'action_controller'
6
+ >> $:.unshift File.join(File.expand_path(File.dirname(__FILE__)), '../../hobosupport/lib')
7
+ >> $:.unshift File.join(File.expand_path(File.dirname(__FILE__)), '../../dryml/lib')
8
+ >> require 'hobosupport'
9
+ >> require 'dryml'
10
+ >> require 'dryml/template_handler'
11
+ >> Dryml.enable
12
+
13
+ {.hidden}
14
+
15
+ >> Dryml.render("hi")
16
+ => "hi"
17
+
18
+ >> Dryml.render("<%= this %>", {:this => "hello"})
19
+ => "hello"
20
+
21
+ >> Dryml.render(%q{<if test="&true">Hi</if><else>Bye</else>})
22
+ => "Hi"
23
+
24
+ >> Dryml.render(%q{<repeat with="&[1,2,3]"><%= this %> </repeat>})
25
+ => "1 2 3 "
26
+
27
+ >> Dryml.render(%q{<def tag="myp"><p param="default"/></def><myp>Hi</myp>})
28
+ => "<p>Hi</p>"
29
+
30
+ >> Dryml.render(%q{<def tag="myp"><p param="default"/></def><call-tag tag="myp">Hi</call-tag>}).strip
31
+ => "<p>Hi</p>"
32
+
33
+ >> Dryml.render(%q{<def tag="myp"><p param="default"/></def><wrap tag="myp" when="&true">img</wrap>}).strip
34
+ => "<p>img</p>"
35
+
36
+ This triggers bug #452, so disabled. FIXME.
37
+
38
+ #>>
39
+ Dryml.render(%q{<def tag="myp">
40
+ <p param="default"/>
41
+ </def>
42
+ <extend tag="myp">
43
+ <old-myp merge>
44
+ <default: replace>Hello <default: restore/></default:>
45
+ </old-myp>
46
+ </extend>
47
+ <myp>World</myp>}).strip
48
+ #=> "<p>Hello World</p>"
49
+
50
+ Test caching
51
+
52
+ >> template = %q{<if test="&x">Hi</if><else>Bye</else>}
53
+ >> t1 = Time.now
54
+ >> Dryml.render(template, {:x => true})
55
+ => "Hi"
56
+ >> t2 = Time.now
57
+ >> Dryml.render(template, {:x => false})
58
+ => "Bye"
59
+ >> t3 = Time.now
60
+
61
+ >> (t3-t2)*1.5 < (t2-t1)
62
+ => true
63
+
64
+ Test descendent searching
65
+
66
+ >> doc = REXML::Document.new '<a><b><c><d a="b">sean</d></c></b></a>'
67
+ >> Dryml::Template.descendent_select(doc.root) { |el| el.attribute 'a' }.size
68
+ => 1