hobo 0.8.5 → 0.8.6
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/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
|