hobo 0.8.5 → 0.8.6
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.txt +41 -0
- data/Manifest +1 -5
- data/Rakefile +10 -3
- data/bin/hobo +38 -15
- data/dryml_generators/rapid/cards.dryml.erb +7 -7
- data/dryml_generators/rapid/pages.dryml.erb +52 -24
- data/hobo.gemspec +42 -322
- data/init.rb +0 -7
- data/lib/active_record/association_collection.rb +9 -0
- data/lib/hobo.rb +13 -14
- data/lib/hobo/accessible_associations.rb +32 -7
- data/lib/hobo/authentication_support.rb +1 -1
- data/lib/hobo/controller.rb +5 -7
- data/lib/hobo/dryml.rb +9 -2
- data/lib/hobo/dryml/dryml_builder.rb +11 -12
- data/lib/hobo/dryml/dryml_doc.rb +22 -24
- data/lib/hobo/dryml/dryml_generator.rb +41 -4
- data/lib/hobo/dryml/part_context.rb +5 -3
- data/lib/hobo/dryml/template.rb +7 -7
- data/lib/hobo/dryml/template_environment.rb +11 -22
- data/lib/hobo/dryml/template_handler.rb +94 -25
- data/lib/hobo/find_for.rb +2 -2
- data/lib/hobo/hobo_helper.rb +21 -21
- data/lib/hobo/include_in_save.rb +9 -5
- data/lib/hobo/lifecycles/transition.rb +2 -2
- data/lib/hobo/model.rb +11 -61
- data/lib/hobo/model_controller.rb +28 -29
- data/lib/hobo/model_router.rb +12 -13
- data/lib/hobo/permissions.rb +47 -37
- data/lib/hobo/permissions/associations.rb +1 -1
- data/lib/hobo/scopes/association_proxy_extensions.rb +5 -6
- data/lib/hobo/scopes/automatic_scopes.rb +7 -4
- data/lib/hobo/tasks/rails.rb +4 -0
- data/lib/hobo/user.rb +0 -1
- data/lib/hobo/user_controller.rb +3 -1
- data/lib/hobo/view_hints.rb +17 -3
- data/rails_generators/hobo/hobo_generator.rb +1 -0
- data/rails_generators/hobo_front_controller/templates/functional_test.rb +1 -11
- data/rails_generators/hobo_front_controller/templates/index.dryml +1 -6
- data/rails_generators/hobo_rapid/hobo_rapid_generator.rb +1 -0
- data/rails_generators/hobo_rapid/templates/hobo-rapid.css +3 -2
- data/rails_generators/hobo_rapid/templates/hobo-rapid.js +24 -15
- data/rails_generators/hobo_rapid/templates/themes/clean/public/stylesheets/clean.css +17 -12
- data/rails_generators/hobo_rapid/templates/themes/clean/public/stylesheets/rapid-ui.css +6 -2
- data/rails_generators/hobo_rapid/templates/themes/clean/views/clean.dryml +2 -2
- data/rails_generators/hobo_user_model/templates/forgot_password.erb +2 -2
- data/rails_generators/hobo_user_model/templates/model.rb +2 -2
- data/taglibs/rapid.dryml +3 -2
- data/taglibs/rapid_core.dryml +21 -16
- data/taglibs/rapid_document_tags.dryml +1 -1
- data/taglibs/rapid_editing.dryml +7 -10
- data/taglibs/rapid_forms.dryml +115 -26
- data/taglibs/rapid_generics.dryml +13 -3
- data/taglibs/rapid_lifecycles.dryml +18 -1
- data/taglibs/rapid_navigation.dryml +50 -61
- data/taglibs/rapid_pages.dryml +103 -19
- data/taglibs/rapid_plus.dryml +54 -6
- data/taglibs/rapid_support.dryml +38 -1
- data/taglibs/rapid_user_pages.dryml +17 -5
- data/test/permissions/models/models.rb +24 -12
- data/test/permissions/models/test.sqlite3 +0 -0
- metadata +6 -15
- data/lib/extensions/test_case.rb +0 -129
- data/lib/hobo/composite_model.rb +0 -73
- data/lib/hobo/model_support.rb +0 -44
- data/tasks/fix_dryml.rake +0 -143
- data/tasks/generate_tag_reference.rake +0 -192
- data/test/dryml/complilation_test.rb +0 -261
data/lib/hobo/model_support.rb
DELETED
@@ -1,44 +0,0 @@
|
|
1
|
-
module Hobo
|
2
|
-
|
3
|
-
module ModelSupport
|
4
|
-
|
5
|
-
# This module provides methods common to both Hobo::Model and Hobo::CompositeModel
|
6
|
-
|
7
|
-
def self.included(base)
|
8
|
-
base.extend(ClassMethods) if base.is_a? Class
|
9
|
-
end
|
10
|
-
|
11
|
-
module ClassMethods
|
12
|
-
|
13
|
-
def delegate_and_compose(*methods)
|
14
|
-
options = methods.pop
|
15
|
-
unless options.is_a?(Hash) && to = options[:to]
|
16
|
-
raise ArgumentError, ("Delegation needs a target. Supply an options hash " +
|
17
|
-
"with a :to key as the last argument (e.g. delegate :hello, :to => :greeter).")
|
18
|
-
end
|
19
|
-
use = options[:use]
|
20
|
-
|
21
|
-
methods.each do |method|
|
22
|
-
module_eval(<<-EOS, "(__COMPOSED_DELEGATION__)", 1)
|
23
|
-
def #{method}
|
24
|
-
@__#{method}_result__ ||= begin
|
25
|
-
obj = #{to}.__send__(#{method.inspect})
|
26
|
-
return nil if obj.nil?
|
27
|
-
|
28
|
-
if obj.nil?
|
29
|
-
nil
|
30
|
-
elsif obj.is_a?(Array)
|
31
|
-
obj.map {|o| self.compose_with(o, #{use.inspect})}
|
32
|
-
else
|
33
|
-
self.compose_with(obj, #{use.inspect})
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
EOS
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
end
|
42
|
-
|
43
|
-
end
|
44
|
-
end
|
data/tasks/fix_dryml.rake
DELETED
@@ -1,143 +0,0 @@
|
|
1
|
-
require 'fileutils'
|
2
|
-
|
3
|
-
def restore_erb_scriptlets(scriptlets, src)
|
4
|
-
src.gsub(/\[!\[HOBO-ERB(\d+)\s*\]!\]/m) {|s| "<%#{scriptlets[$1.to_i]}%>" }
|
5
|
-
end
|
6
|
-
|
7
|
-
|
8
|
-
def fix_nodes(nodes)
|
9
|
-
nodes.map{|x| fix_element(x) if x.is_a?(REXML::Element) }
|
10
|
-
end
|
11
|
-
|
12
|
-
|
13
|
-
def start_tag_replace(el, repl)
|
14
|
-
i, len = el.source_offset, el.start_tag_source.length
|
15
|
-
@src[i..i+len-1] = repl
|
16
|
-
end
|
17
|
-
|
18
|
-
|
19
|
-
def classes?
|
20
|
-
ENV['CLASS']
|
21
|
-
end
|
22
|
-
|
23
|
-
def ids?
|
24
|
-
ENV['ID']
|
25
|
-
end
|
26
|
-
|
27
|
-
|
28
|
-
def string_interpolate_safe_dasherize(s)
|
29
|
-
token = "[[MAKE_ME_A_DASH!]]"
|
30
|
-
s.gsub("_", token).
|
31
|
-
gsub(/\#\{.*?\}/) {|s2| s2.gsub(token, "_") }.
|
32
|
-
gsub(token, "-")
|
33
|
-
end
|
34
|
-
|
35
|
-
|
36
|
-
def fix_children(element, template_params)
|
37
|
-
element.elements.to_a.reverse.each do |e|
|
38
|
-
# recurse first - we're going backwards
|
39
|
-
is_template_call = e.dryml_name =~ /^[A-Z]/ && !e.attribute("replace")
|
40
|
-
fix_children(e, is_template_call)
|
41
|
-
|
42
|
-
fixed = fix_element(e, template_params)
|
43
|
-
start_tag_replace(e, fixed)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
|
48
|
-
def fix_element(e, template_param)
|
49
|
-
tag = e.start_tag_source.dup
|
50
|
-
|
51
|
-
if e.dryml_name == "tagbody"
|
52
|
-
tag.sub!("<tagbody", '<do param="default"')
|
53
|
-
elsif e.dryml_name == "default_tagbody"
|
54
|
-
tag.sub!("<default_tagbody", '<param-content')
|
55
|
-
else
|
56
|
-
tag.sub!("<#{e.dryml_name}", "<#{e.dryml_name.underscore.dasherize}#{':' if template_param}")
|
57
|
-
end
|
58
|
-
|
59
|
-
start = e.expanded_name.length+1
|
60
|
-
tag[start..-1] = tag[start..-1].gsub(/([A-Za-z_]+)(\s*=\s*("(.*?)"|'(.*?)'))?/) do |s|
|
61
|
-
_, name, _, value = *Regexp.last_match
|
62
|
-
|
63
|
-
s.sub!(/^#{name}/, name.dasherize)
|
64
|
-
|
65
|
-
if value
|
66
|
-
# underscore / dasherize the values of various attributes
|
67
|
-
|
68
|
-
if e.name == "def" && name.in?(%w(tag attrs alias_of extend_with))
|
69
|
-
s.sub!(/#{Regexp.escape(value)}$/) {|v| v.underscore.dasherize}
|
70
|
-
|
71
|
-
elsif name.in?(%w(part update)) || (classes? && name == 'class') || (ids? && name == 'id')
|
72
|
-
s.sub!(/#{Regexp.escape(value)}$/) {|v| string_interpolate_safe_dasherize(v) }
|
73
|
-
|
74
|
-
elsif name == "param"
|
75
|
-
s.sub!(/#{Regexp.escape(value)}$/) {|v| string_interpolate_safe_dasherize(v.underscore) }
|
76
|
-
end
|
77
|
-
|
78
|
-
end
|
79
|
-
s
|
80
|
-
end
|
81
|
-
tag
|
82
|
-
end
|
83
|
-
|
84
|
-
|
85
|
-
def fix_file(filename)
|
86
|
-
puts "Fixing #{filename}"
|
87
|
-
src = File.read(filename)
|
88
|
-
|
89
|
-
# Ripped from Hobo::Dryml::Template - hide erb scriptlets and parse with REXML
|
90
|
-
scriptlets = {}
|
91
|
-
src = src.gsub(/<%(.*?)%>/m) do
|
92
|
-
_, scriptlet = *Regexp.last_match
|
93
|
-
id = scriptlets.size + 1
|
94
|
-
scriptlets[id] = scriptlet
|
95
|
-
newlines = "\n" * scriptlet.count("\n")
|
96
|
-
"[![HOBO-ERB#{id}#{newlines}]!]"
|
97
|
-
end
|
98
|
-
|
99
|
-
# DRYML doesn't have to have a single root - add one to keep REXML
|
100
|
-
# happy
|
101
|
-
@src = "<root>" + src + "</root>"
|
102
|
-
begin
|
103
|
-
doc = Hobo::Dryml::Parser::Document.new(Hobo::Dryml::Parser::Source.new(@src))
|
104
|
-
rescue REXML::ParseException => e
|
105
|
-
raise Exception, "File: #{@template_path}\n#{e}"
|
106
|
-
end
|
107
|
-
|
108
|
-
fix_children(doc[0], false)
|
109
|
-
|
110
|
-
#Fix close tags
|
111
|
-
@src.gsub!(/<\/[^:>]*/) { |s| s.underscore.dasherize }
|
112
|
-
@src.gsub!(/<\/tagbody\s*>/, "</do>")
|
113
|
-
|
114
|
-
# Strip the root tag we added
|
115
|
-
@src.sub!(/^<root>/, "")
|
116
|
-
@src.sub!(/<\/root>$/, "")
|
117
|
-
|
118
|
-
fixed = restore_erb_scriptlets(scriptlets, @src)
|
119
|
-
File.open(filename, 'w') { |f| f.write(fixed) }
|
120
|
-
end
|
121
|
-
|
122
|
-
|
123
|
-
namespace :hobo do
|
124
|
-
|
125
|
-
desc "Replace old-style DRYML source code with CamelCaseTags and underscores with new DRYML syntax"
|
126
|
-
task :fixdryml => :environment do
|
127
|
-
|
128
|
-
dir = ENV['DIR']._?.sub(/\/$/, '') || "app/views"
|
129
|
-
|
130
|
-
# Make a backup
|
131
|
-
backup_dir = "#{dir.gsub('../', '').gsub('/', '_')}_before_fixdryml"
|
132
|
-
if File.exist?(backup_dir)
|
133
|
-
puts "Backup (#{backup_dir}) already exists - be careful! (nothing changed)"
|
134
|
-
exit
|
135
|
-
end
|
136
|
-
FileUtils.cp_r(dir, backup_dir)
|
137
|
-
|
138
|
-
Dir["#{dir}/**/*.dryml"].each do |f|
|
139
|
-
fix_file(f)
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
end
|
@@ -1,192 +0,0 @@
|
|
1
|
-
require 'fileutils'
|
2
|
-
|
3
|
-
ActiveSupport::Dependencies.load_paths << File.dirname(__FILE__) + "/../lib"
|
4
|
-
|
5
|
-
require 'rexml/xpath'
|
6
|
-
XPath = REXML::XPath
|
7
|
-
|
8
|
-
def tag_title(tag, link=false)
|
9
|
-
if tag.is_a? String
|
10
|
-
name = tag
|
11
|
-
anchor = tag
|
12
|
-
else
|
13
|
-
for_attr = tag.attributes['for'] and for_decl = %( for=`"#{for_attr}"`)
|
14
|
-
name = tag.attributes['tag']
|
15
|
-
anchor = tag_anchor(tag)
|
16
|
-
end
|
17
|
-
|
18
|
-
title = "<#{name}#{for_decl}>"
|
19
|
-
|
20
|
-
if link
|
21
|
-
"[#{title}](##{anchor})"
|
22
|
-
else
|
23
|
-
title
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
|
28
|
-
def link_to_tag(tag)
|
29
|
-
tag_title(tag, true)
|
30
|
-
end
|
31
|
-
|
32
|
-
|
33
|
-
def tag_anchor(element)
|
34
|
-
for_attr = element.attributes['for']
|
35
|
-
name = element.attributes['tag']
|
36
|
-
|
37
|
-
if for_attr
|
38
|
-
"#{name}--for-#{for_attr}"
|
39
|
-
else
|
40
|
-
name
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
|
45
|
-
def comment_for_tag(element)
|
46
|
-
space = element.previous_sibling and
|
47
|
-
space.to_s.blank? && space.to_s.count("\n") == 1 and
|
48
|
-
comment = space.previous_sibling
|
49
|
-
|
50
|
-
comment.to_s.strip if comment.is_a?(REXML::Comment)
|
51
|
-
end
|
52
|
-
|
53
|
-
|
54
|
-
def doc_for_tag(tagdef)
|
55
|
-
comment = comment_for_tag(tagdef)
|
56
|
-
|
57
|
-
params_merged_with = XPath.first(tagdef, ".//*[@merge|@merge-params]")._?.name
|
58
|
-
params_merged_with &&= "(merged with #{link_to_tag params_merged_with})"
|
59
|
-
|
60
|
-
attrs_merged_with = XPath.first(tagdef, ".//*[@merge|@merge-attrs]")._?.name
|
61
|
-
attrs_merged_with &&= "(merged with #{link_to_tag attrs_merged_with})"
|
62
|
-
|
63
|
-
attrs = tagdef.attributes['attrs'] || []
|
64
|
-
attrs = attrs.split(/,\s*/).where_not.blank?.map { |a| " * #{a}\n" }.join
|
65
|
-
|
66
|
-
parameters = params_to_list(get_parameters(tagdef))
|
67
|
-
<<-END
|
68
|
-
---
|
69
|
-
|
70
|
-
<a name="#{tag_anchor tagdef}"> </a>
|
71
|
-
## #{tag_title tagdef}
|
72
|
-
|
73
|
-
#{comment}
|
74
|
-
|
75
|
-
### Attributes #{attrs_merged_with}
|
76
|
-
|
77
|
-
#{attrs.blank? ? 'None' : attrs}
|
78
|
-
|
79
|
-
### Parameters #{params_merged_with}
|
80
|
-
|
81
|
-
#{parameters.blank? ? 'None' : parameters}
|
82
|
-
END
|
83
|
-
end
|
84
|
-
|
85
|
-
|
86
|
-
def get_parameters(elem)
|
87
|
-
result = []
|
88
|
-
elem.elements.each do |e|
|
89
|
-
if e.attributes['param']
|
90
|
-
result << [e, get_parameters(e)]
|
91
|
-
else
|
92
|
-
result.concat(get_parameters(e))
|
93
|
-
end
|
94
|
-
end
|
95
|
-
result
|
96
|
-
end
|
97
|
-
|
98
|
-
|
99
|
-
def params_to_list(params, indent=" ")
|
100
|
-
items = params.map do |elem, sub_params|
|
101
|
-
p_attr = elem.attributes['param']
|
102
|
-
entry = if p_attr == "&true"
|
103
|
-
"<#{elem.name}:>"
|
104
|
-
elsif p_attr =~ /#\{/
|
105
|
-
"(dynamic parameter) (<#{elem.name}>)"
|
106
|
-
else
|
107
|
-
"<#{p_attr}:> (<#{elem.name}>)"
|
108
|
-
end
|
109
|
-
sub_list = params_to_list(sub_params, indent + ' ') unless sub_params.empty?
|
110
|
-
"<li>#{entry}\n#{sub_list}</li>\n"
|
111
|
-
end.join
|
112
|
-
|
113
|
-
items.any? ? "<ul>#{items}</ul>" : ""
|
114
|
-
end
|
115
|
-
|
116
|
-
|
117
|
-
def contents(root)
|
118
|
-
tags = XPath.match(root, '/*/*[@tag]')
|
119
|
-
tags.map { |tag| " * #{link_to_tag tag}\n" }.join
|
120
|
-
end
|
121
|
-
|
122
|
-
|
123
|
-
def doc_for_taglib(title, root)
|
124
|
-
tags = XPath.match(root, '/*/*[@tag]').map { |e| doc_for_tag(e) }.join("\n\n")
|
125
|
-
|
126
|
-
"# #{title}\n\n" + contents(root) + "\n\n" + tags
|
127
|
-
end
|
128
|
-
|
129
|
-
def index_page(output_files, output_dir)
|
130
|
-
markdown = "# Tag Documentation\n\n" + output_files.map do |f|
|
131
|
-
link = f.gsub(output_dir+'/', '')
|
132
|
-
link_text = link.gsub('_', '\_').gsub(/\.html$/, '')
|
133
|
-
"* [#{link_text}](#{link})"
|
134
|
-
end.join("\n")
|
135
|
-
|
136
|
-
html = Maruku.new(markdown).to_html
|
137
|
-
|
138
|
-
File.open("#{output_dir}/index.html", 'w') { |f| f.write(html) }
|
139
|
-
end
|
140
|
-
|
141
|
-
def process_directory(src, output_dir, output_format)
|
142
|
-
raise RuntimeError, "#{output_dir} is not a directory" if File.exists?(output_dir) && !File.directory?(output_dir)
|
143
|
-
|
144
|
-
FileUtils.mkdir output_dir unless File.exists? output_dir
|
145
|
-
|
146
|
-
dryml_files = File.directory?(src) ? Dir["#{src}/*"] : [src]
|
147
|
-
|
148
|
-
output_files = []
|
149
|
-
|
150
|
-
dryml_files.each do |f|
|
151
|
-
if File.directory?(f)
|
152
|
-
output_files += process_directory(f, "#{output_dir}/#{File.basename(f)}", output_format)
|
153
|
-
elsif f =~ /\.dryml$/
|
154
|
-
basename = File.basename(f).sub(/\.dryml$/, '')
|
155
|
-
title = basename.titleize
|
156
|
-
|
157
|
-
doc = Hobo::Dryml::Parser::Document.new(File.read(f), f)
|
158
|
-
|
159
|
-
output = doc.restore_erb_scriptlets(doc_for_taglib(title, doc))
|
160
|
-
output = Maruku.new(output).to_html.gsub('&', '&') if output_format == 'html'
|
161
|
-
|
162
|
-
output_file = "#{output_dir}/#{basename}.#{output_format}"
|
163
|
-
puts output_file
|
164
|
-
File.open(output_file, 'w') { |f| f.write(output) }
|
165
|
-
output_files << output_file
|
166
|
-
end
|
167
|
-
end
|
168
|
-
output_files
|
169
|
-
end
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
namespace :hobo do
|
174
|
-
|
175
|
-
desc "Generate markdown formatted reference docs automatically from DRYML taglibs"
|
176
|
-
task :generate_tag_reference => :environment do
|
177
|
-
gem 'maruku'
|
178
|
-
require 'maruku'
|
179
|
-
|
180
|
-
src = ENV['src']
|
181
|
-
|
182
|
-
output_dir = ENV['output'] || "taglib-docs"
|
183
|
-
|
184
|
-
output_format = ENV['format'] || "markdown"
|
185
|
-
|
186
|
-
output_files = process_directory(src, output_dir, output_format)
|
187
|
-
|
188
|
-
index_page(output_files, output_dir)
|
189
|
-
end
|
190
|
-
|
191
|
-
end
|
192
|
-
|
@@ -1,261 +0,0 @@
|
|
1
|
-
require "#{File.dirname __FILE__}/dryml_test_case"
|
2
|
-
|
3
|
-
class CompilationTest < DrymlTestCase
|
4
|
-
|
5
|
-
should "compile tag calls as method calls" do
|
6
|
-
assert_compiles_to "<% _output(foo.to_s) %>", "<foo/>"
|
7
|
-
end
|
8
|
-
|
9
|
-
should "convert dashes in tag names to underscores in compiled method calls" do
|
10
|
-
assert_compiles_to "<% _output(foo_baa.to_s) %>", "<foo-baa/>"
|
11
|
-
end
|
12
|
-
|
13
|
-
should "compile attributes as keyword parameters" do
|
14
|
-
assert_compiles_to '<% _output(foo({:a => "1", :b => "2"}, {})) %>', "<foo a='1' b='2'/>"
|
15
|
-
end
|
16
|
-
|
17
|
-
should "convert attribute names with dashes in tag calls to symbols with underscores" do
|
18
|
-
assert_compiles_to "<% _output(foo({:my_attribute => \"1\"}, {})) %>", "<foo my-attribute='1'/>"
|
19
|
-
end
|
20
|
-
|
21
|
-
should "compile code attributes as ruby code" do
|
22
|
-
assert_compiles_to '<% _output(foo({:a => (1 + 2)}, {})) %>', "<foo a='&1 + 2'/>"
|
23
|
-
end
|
24
|
-
|
25
|
-
should "compile attributes with no RHS as passing `true`" do
|
26
|
-
assert_compiles_to '<% _output(foo({:a => (true)}, {})) %>', "<foo a/>"
|
27
|
-
end
|
28
|
-
|
29
|
-
should "compile content of a tag call as the default parameter" do
|
30
|
-
assert_compiles_to "<% _output(foo({}, { :default => proc { |_foo__default_content| new_context { %>the body<% } }, })) %>",
|
31
|
-
"<foo>the body</foo>"
|
32
|
-
end
|
33
|
-
|
34
|
-
should "support <param_content/> inside the content of a tag" do
|
35
|
-
src = "<foo>!!<param-content/>??</foo>"
|
36
|
-
assert_compiles_to "<% _output(foo({}, { :default => proc { |_foo__default_content| new_context { %>!!<%= _foo__default_content && _foo__default_content.call %>??<% } }, })) %>", src
|
37
|
-
end
|
38
|
-
|
39
|
-
should "support the 'for' attribute on <param-content/>" do
|
40
|
-
src = "<x><y>123<param-content for='x'/>456</y></x>"
|
41
|
-
assert_compiles_to(
|
42
|
-
"<% _output(x({}, { :default => proc { |_x__default_content| new_context { %><% _output(y({}, { :default => proc { |_y__default_content| new_context { %>" +
|
43
|
-
"123<%= _x__default_content && _x__default_content.call %>456" +
|
44
|
-
"<% } }, })) %><% } }, })) %>", src)
|
45
|
-
end
|
46
|
-
|
47
|
-
should "allow :foo as a shorthand for field='foo' on tags" do
|
48
|
-
assert_compiles_to '<% _output(foo({:field => "name"}, {})) %>', "<foo:name/>"
|
49
|
-
end
|
50
|
-
|
51
|
-
should "allow static tag names like :title as a shorthand for field='title'" do
|
52
|
-
assert_compiles_to '<% _output(foo({:field => "name"}, {})) %>', "<foo:name/>"
|
53
|
-
end
|
54
|
-
|
55
|
-
should "allow close tags to ommit the :field_name part" do
|
56
|
-
assert_compiles_to '<% _output(foo({:field => "name"}, { :default => proc { |_foo__default_content| new_context { %><% } }, })) %>', "<foo:name></foo>"
|
57
|
-
|
58
|
-
end
|
59
|
-
|
60
|
-
should "compile tag calls with merge-attrs" do
|
61
|
-
assert_compiles_to "<% _output(foo(merge_attrs({},(attributes) || {}), {})) %>", "<foo merge-attrs/>"
|
62
|
-
assert_compiles_to '<% _output(foo(merge_attrs({:a => "1"},(attributes) || {}), {})) %>', "<foo a='1' merge-attrs/>"
|
63
|
-
end
|
64
|
-
|
65
|
-
|
66
|
-
# --- Compilation: Defining Tags --- #
|
67
|
-
|
68
|
-
should "compile defs" do
|
69
|
-
assert_compiles_to(
|
70
|
-
"<% def foo(all_attributes={}, all_parameters={}); " +
|
71
|
-
"parameters = Hobo::Dryml::TagParameters.new(all_parameters, []); " +
|
72
|
-
"all_parameters = Hobo::Dryml::TagParameters.new(all_parameters); " +
|
73
|
-
"_tag_context(all_attributes) do attributes, = _tag_locals(all_attributes, []) %>" +
|
74
|
-
"<% _erbout; end; end %>",
|
75
|
-
|
76
|
-
"<def tag='foo'></def>")
|
77
|
-
|
78
|
-
end
|
79
|
-
|
80
|
-
should "compile attrs in defs as local variables" do
|
81
|
-
assert_compiles_to(
|
82
|
-
"<% def foo(all_attributes={}, all_parameters={}); " +
|
83
|
-
"parameters = Hobo::Dryml::TagParameters.new(all_parameters, []); " +
|
84
|
-
"all_parameters = Hobo::Dryml::TagParameters.new(all_parameters); " +
|
85
|
-
"_tag_context(all_attributes) do " +
|
86
|
-
"a, my_attr, attributes, = _tag_locals(all_attributes, [:a, :my_attr]) %>" +
|
87
|
-
"<% _erbout; end; end %>",
|
88
|
-
|
89
|
-
"<def tag='foo' attrs='a, my-attr'></def>")
|
90
|
-
end
|
91
|
-
|
92
|
-
should "dissallow `param` outside of tag definitions" do
|
93
|
-
assert_raise(DrymlException) { compile_dryml("<foo param/>") }
|
94
|
-
end
|
95
|
-
|
96
|
-
should "compile param-tag calls as calls to `call_tag_parameter`" do
|
97
|
-
assert_compiles_to '<% _output(call_tag_parameter(:foo, {:a => "1"}, {}, all_parameters, :foo)) %>',
|
98
|
-
"<foo param a='1'/>",
|
99
|
-
:in_def
|
100
|
-
end
|
101
|
-
|
102
|
-
should "compile with support for named params" do
|
103
|
-
assert_compiles_to "<% _output(call_tag_parameter(:foo, {}, {}, all_parameters, :zap)) %>", "<foo param='zap'/>", :in_def
|
104
|
-
end
|
105
|
-
|
106
|
-
should "compile a param tag-call with a body" do
|
107
|
-
assert_compiles_to "<% _output(call_tag_parameter(:foo, {}, { :default => proc { |_foo__default_content| new_context { %>abc<% } }, }, all_parameters, :foo)) %>",
|
108
|
-
"<foo param>abc</foo>",
|
109
|
-
:in_def
|
110
|
-
end
|
111
|
-
|
112
|
-
should "compile a param tag-call with a body and a call to <param_content/>" do
|
113
|
-
assert_compiles_to "<% _output(call_tag_parameter(:foo, {}, { :default => proc { |_foo__default_content| new_context { %>!!<%= _foo__default_content && _foo__default_content.call %>!!<% } }, }, all_parameters, :foo)) %>",
|
114
|
-
"<foo param>!!<param-content/>!!</foo>",
|
115
|
-
:in_def
|
116
|
-
|
117
|
-
end
|
118
|
-
|
119
|
-
should "compile param template-calls as calls to `call_tag_parameter`" do
|
120
|
-
assert_compiles_to "<% _output(call_tag_parameter(:foo, {}, {}, all_parameters, :foo)) %>",
|
121
|
-
"<foo param/>",
|
122
|
-
:in_def
|
123
|
-
end
|
124
|
-
|
125
|
-
should "compile param tag calls with parameters as calls to `call_tag_parameter`" do
|
126
|
-
assert_compiles_to '<% _output(call_tag_parameter(:foo, {}, {:a => proc { [{:x => "1"}, {}] }, }, all_parameters, :foo)) %>',
|
127
|
-
"<foo param><a: x='1'/></foo>",
|
128
|
-
:in_def
|
129
|
-
end
|
130
|
-
|
131
|
-
should "compile parameters with param" do
|
132
|
-
assert_compiles_to '<% _output(foo({}, {:abc => merge_tag_parameter(proc { [{}, {}] }, all_parameters[:abc]), })) %>',
|
133
|
-
"<foo><abc: param/></foo>",
|
134
|
-
:in_def
|
135
|
-
end
|
136
|
-
|
137
|
-
should "compile tag parameters with named params" do
|
138
|
-
assert_compiles_to '<% _output(foo({}, {:abc => merge_tag_parameter(proc { [{}, {}] }, all_parameters[:x]), })) %>',
|
139
|
-
"<foo><abc: param='x'/></foo>",
|
140
|
-
:in_def
|
141
|
-
end
|
142
|
-
|
143
|
-
should "compile tag parameters with param and attributes" do
|
144
|
-
assert_compiles_to '<% _output(foo({}, {:abc => merge_tag_parameter(proc { [{:a => "b"}, {}] }, all_parameters[:x]), })) %>',
|
145
|
-
"<foo><abc: param='x' a='b'/></foo>",
|
146
|
-
:in_def
|
147
|
-
end
|
148
|
-
|
149
|
-
should "compile tag parameters with param and a tag body" do
|
150
|
-
assert_compiles_to(
|
151
|
-
'<% _output(foo({}, {:abc => merge_tag_parameter(' +
|
152
|
-
'proc { [{}, { :default => proc { |_abc__default_content| new_context { %>ha!<% } }, }] }, all_parameters[:abc]), })) %>',
|
153
|
-
"<foo><abc: param>ha!</abc></foo>",
|
154
|
-
:in_def)
|
155
|
-
|
156
|
-
end
|
157
|
-
|
158
|
-
should "compile tag parameters with param and nested parameters" do
|
159
|
-
assert_compiles_to(
|
160
|
-
'<% _output(foo({}, {:baa => merge_tag_parameter(' +
|
161
|
-
'proc { [{}, {:x => proc { [{}, { :default => proc { |_x__default_content| new_context { %>hello<% } }, }] }, }] }, all_parameters[:baa]), })) %>',
|
162
|
-
"<foo><baa: param><x:>hello</x:></baa:></foo>",
|
163
|
-
:in_def)
|
164
|
-
end
|
165
|
-
|
166
|
-
# --- Compilation: Calling tags with parameters --- #
|
167
|
-
|
168
|
-
should "compile tag parameters as procs" do
|
169
|
-
assert_compiles_to(
|
170
|
-
'<% _output(foo({}, {' +
|
171
|
-
':x => proc { [{}, { :default => proc { |_x__default_content| new_context { %>hello<% } }, }] }, ' +
|
172
|
-
':y => proc { [{}, { :default => proc { |_y__default_content| new_context { %>world<% } }, }] }, })) %>',
|
173
|
-
"<foo><x:>hello</x><y:>world</y:></foo>"
|
174
|
-
)
|
175
|
-
end
|
176
|
-
|
177
|
-
should "compile tag parameters with attributes" do
|
178
|
-
assert_compiles_to(
|
179
|
-
'<% _output(foo({}, {:abc => proc { [{:x => "1"}, { :default => proc { |_abc__default_content| new_context { %>hello<% } }, }] }, })) %>',
|
180
|
-
"<foo><abc: x='1'>hello</abc></foo>"
|
181
|
-
)
|
182
|
-
end
|
183
|
-
|
184
|
-
should "allow :foo as a shorthand for field='foo' on template tags" do
|
185
|
-
assert_compiles_to '<% _output(foo({:field => "name"}, {})) %>', "<foo:name/>"
|
186
|
-
end
|
187
|
-
|
188
|
-
should "compile template parameters which are themselves templates" do
|
189
|
-
# Tag parameters with nested tag parameters are procs that return
|
190
|
-
# a pair of hashes, the first is the attributes, the second is the
|
191
|
-
# sub-template procs
|
192
|
-
assert_compiles_to(
|
193
|
-
'<% _output(foo({}, ' +
|
194
|
-
'{:baa => proc { [{:x => "1"}, {:a => proc { [{}, { :default => proc { |_a__default_content| new_context { %>hello<% } }, }] }, }] }, })) %>',
|
195
|
-
"<foo><baa: x='1'><a:>hello</a></baa></foo>")
|
196
|
-
end
|
197
|
-
|
198
|
-
should "compile 'replace' parameters" do
|
199
|
-
# A replace parameter is detected at runtime by the arity of the
|
200
|
-
# block == 1 (for a normal parameter it would be 0). See
|
201
|
-
# TemplateEnvironment#call_tag_parameter
|
202
|
-
assert_compiles_to(
|
203
|
-
'<% _output(page({}, {:head_replacement => proc { |_head_restore| new_context { %>abc<% } }, })) %>',
|
204
|
-
"<page><head: replace>abc</head></page>"
|
205
|
-
)
|
206
|
-
end
|
207
|
-
|
208
|
-
should "compile 'replace' parameters where the restore contains a default parameter call" do
|
209
|
-
assert_compiles_to(
|
210
|
-
'<% _output(page({}, {:head_replacement => proc { |_head_restore| new_context { %>abc ' +
|
211
|
-
'<% _output(_head_restore.call({}, { :default => proc { |_head__default_content| new_context { %>blah<% } }, })) %>' +
|
212
|
-
'<% } }, })) %>',
|
213
|
-
|
214
|
-
"<page><head: replace>abc <head restore>blah</head></head></page>"
|
215
|
-
)
|
216
|
-
end
|
217
|
-
|
218
|
-
should "compile 'replace' tag parameters with a default parameter call" do
|
219
|
-
assert_compiles_to(
|
220
|
-
'<% _output(page({}, {:head_replacement => proc { |_head_restore| new_context { %>abc ' +
|
221
|
-
'<% _output(_head_restore.call({}, {})) %>' +
|
222
|
-
'<% } }, })) %>',
|
223
|
-
"<page><head: replace>abc <head restore/></head></page>")
|
224
|
-
end
|
225
|
-
|
226
|
-
|
227
|
-
# --- Compilation: Syntax sugar for before, after, append, prepend --- #
|
228
|
-
|
229
|
-
should "compile 'before' parameters" do
|
230
|
-
assert_compiles_to(
|
231
|
-
'<% _output(page({}, {:head_replacement => proc { |_head_restore| new_context { %>abc' +
|
232
|
-
'<% _output(_head_restore.call({}, {})) %>' +
|
233
|
-
'<% } }, })) %>',
|
234
|
-
"<page><before-head:>abc</before-head></page>")
|
235
|
-
end
|
236
|
-
|
237
|
-
should "compile 'after' parameters" do
|
238
|
-
assert_compiles_to(
|
239
|
-
'<% _output(page({}, {:head_replacement => proc { |_head_restore| new_context { %>' +
|
240
|
-
'<% _output(_head_restore.call({}, {})) %>' +
|
241
|
-
'abc<% } }, })) %>',
|
242
|
-
"<page><after-head:>abc</after-head></page>")
|
243
|
-
end
|
244
|
-
|
245
|
-
should "compile 'apppend' parameters" do
|
246
|
-
assert_compiles_to(
|
247
|
-
'<% _output(page({}, {:head => proc { [{}, { :default => proc { |_head__default_content| new_context { %>' +
|
248
|
-
'<%= _head__default_content && _head__default_content.call %>:o)' +
|
249
|
-
'<% } } } ] }, })) %>',
|
250
|
-
"<page><append-head:>:o)</append-head></page>")
|
251
|
-
end
|
252
|
-
|
253
|
-
should "compile 'prepend' parameters" do
|
254
|
-
assert_compiles_to(
|
255
|
-
'<% _output(page({}, {:head => proc { [{}, { :default => proc { |_head__default_content| new_context { %>' +
|
256
|
-
':o)<%= _head__default_content && _head__default_content.call %>' +
|
257
|
-
'<% } } } ] }, })) %>',
|
258
|
-
"<page><prepend-head:>:o)</prepend-head></page>")
|
259
|
-
end
|
260
|
-
|
261
|
-
end
|