dryml 1.1.0.pre0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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