zafu 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/History.txt +9 -0
- data/README.rdoc +56 -0
- data/Rakefile +56 -0
- data/lib/zafu/all.rb +17 -0
- data/lib/zafu/compiler.rb +7 -0
- data/lib/zafu/controller_methods.rb +49 -0
- data/lib/zafu/handler.rb +57 -0
- data/lib/zafu/info.rb +4 -0
- data/lib/zafu/markup.rb +186 -0
- data/lib/zafu/mock_helper.rb +42 -0
- data/lib/zafu/node_context.rb +96 -0
- data/lib/zafu/parser.rb +564 -0
- data/lib/zafu/parsing_rules.rb +257 -0
- data/lib/zafu/process/ajax.rb +90 -0
- data/lib/zafu/process/conditional.rb +45 -0
- data/lib/zafu/process/context.rb +45 -0
- data/lib/zafu/process/html.rb +168 -0
- data/lib/zafu/process/ruby_less.rb +145 -0
- data/lib/zafu/template.rb +25 -0
- data/lib/zafu/test_helper.rb +19 -0
- data/lib/zafu.rb +7 -0
- data/rails/init.rb +1 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/test/markup_test.rb +232 -0
- data/test/mock/params.rb +19 -0
- data/test/node_context_test.rb +190 -0
- data/test/ruby_less_test.rb +37 -0
- data/test/test_helper.rb +9 -0
- data/test/zafu_test.rb +57 -0
- data/zafu.gemspec +83 -0
- metadata +124 -0
@@ -0,0 +1,145 @@
|
|
1
|
+
require 'rubyless'
|
2
|
+
|
3
|
+
module Zafu
|
4
|
+
module Process
|
5
|
+
module RubyLess
|
6
|
+
include ::RubyLess::SafeClass
|
7
|
+
# Actual method resolution. The lookup first starts in the current helper. If nothing is found there, it
|
8
|
+
# searches inside a 'helpers' module and finally looks into the current node_context.
|
9
|
+
# If nothing is found at this stage, we prepend the method with the current node and start over again.
|
10
|
+
def safe_method_type(signature)
|
11
|
+
get_method_type(signature, false)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Resolve unknown methods by using RubyLess in the current compilation context (the
|
15
|
+
# translate method in RubyLess will call 'safe_method_type' in this module).
|
16
|
+
def r_unknown
|
17
|
+
rubyless_render(@method, @params)
|
18
|
+
rescue ::RubyLess::NoMethodError => err
|
19
|
+
parser_error("#{err.error_message} <span class='type'>#{err.method_with_arguments}</span>", err.receiver_with_class)
|
20
|
+
rescue ::RubyLess::Error => err
|
21
|
+
parser_error(err.message)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Print documentation on the current node type.
|
25
|
+
def r_m
|
26
|
+
if @params[:helper] == 'true'
|
27
|
+
klass = helper.class
|
28
|
+
else
|
29
|
+
klass = node.klass
|
30
|
+
end
|
31
|
+
|
32
|
+
out "<div class='rubyless-m'><h3>Documentation for <b>#{klass}</b></h3>"
|
33
|
+
out "<ul>"
|
34
|
+
::RubyLess::SafeClass.safe_methods_for(klass).each do |signature, opts|
|
35
|
+
opts = opts.dup
|
36
|
+
opts.delete(:method)
|
37
|
+
if opts.keys == [:class]
|
38
|
+
opts = opts[:class]
|
39
|
+
end
|
40
|
+
out "<li>#{signature.inspect} => #{opts.inspect}</li>"
|
41
|
+
end
|
42
|
+
out "</ul></div>"
|
43
|
+
end
|
44
|
+
|
45
|
+
# TEMPORARY METHOD DURING HACKING...
|
46
|
+
def r_erb
|
47
|
+
"<pre><%= @erb.gsub('<','<').gsub('>','>') %></pre>"
|
48
|
+
end
|
49
|
+
|
50
|
+
def rubyless_render(method, params)
|
51
|
+
rubyless_expand(::RubyLess.translate(method_with_arguments(method, params), self))
|
52
|
+
end
|
53
|
+
|
54
|
+
def rubyless_attr(val)
|
55
|
+
::RubyLess.translate_string(val, self)
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
def get_method_type(signature, added_options = false)
|
60
|
+
if type = node_context_from_signature(signature)
|
61
|
+
# Resolve @page, @node
|
62
|
+
type
|
63
|
+
elsif type = safe_method_from(helper, signature)
|
64
|
+
# Resolve template helper methods
|
65
|
+
type
|
66
|
+
elsif helper.respond_to?(:helpers) && type = safe_method_from(helper.helpers, signature)
|
67
|
+
# Resolve by looking at the included helpers
|
68
|
+
type
|
69
|
+
elsif node && node.klass.kind_of?(Class) && type = safe_method_from(node.klass, signature)
|
70
|
+
# Resolve node context methods (xxx.foo, xxx.bar)
|
71
|
+
type.merge(:method => "#{node.name}.#{type[:method]}")
|
72
|
+
elsif node && !added_options
|
73
|
+
# Try prepending current node before arguments: link("foo") becomse link(var1, "foo")
|
74
|
+
signature_with_node = signature.dup
|
75
|
+
signature_with_node.insert(1, node.klass)
|
76
|
+
if type = get_method_type(signature_with_node, added_options = true)
|
77
|
+
type = type.merge(:prepend_args => ::RubyLess::TypedString.new(node.name, :class => node.klass))
|
78
|
+
type
|
79
|
+
else
|
80
|
+
nil
|
81
|
+
end
|
82
|
+
else
|
83
|
+
nil
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def method_with_arguments(method, params)
|
88
|
+
hash_arguments = {}
|
89
|
+
arguments = []
|
90
|
+
keys = params.keys.map {|k| k.to_s}
|
91
|
+
keys.sort.each do |k|
|
92
|
+
if k.to_s =~ /\A_/
|
93
|
+
arguments << params[k.to_sym]
|
94
|
+
else
|
95
|
+
hash_arguments[k.to_s] = params[k.to_sym]
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
arguments += [hash_arguments] if hash_arguments != {}
|
100
|
+
if arguments != [] && method[-1..-1] =~ /\w/
|
101
|
+
"#{method}(#{arguments.inspect[1..-2]})"
|
102
|
+
else
|
103
|
+
method
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def rubyless_expand(res)
|
108
|
+
if res.klass == String && @blocks.map {|b| b.kind_of?(String) ? nil : b.method}.compact.empty?
|
109
|
+
out "<%= #{res} %>"
|
110
|
+
elsif res.could_be_nil?
|
111
|
+
out "<% if #{var} = #{res} -%>"
|
112
|
+
out @markup.wrap(expand_with_node(var, res.klass))
|
113
|
+
out "<% end -%>"
|
114
|
+
else
|
115
|
+
out "<% #{var} = #{res} -%>"
|
116
|
+
out @markup.wrap(expand_with_node(var, res.klass))
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# This is used to resolve '@node' as NodeContext with class Node, '@page' as first NodeContext
|
121
|
+
# of type Page, etc.
|
122
|
+
def node_context_from_signature(signature)
|
123
|
+
return nil unless signature.size == 1
|
124
|
+
ivar = signature.first
|
125
|
+
return nil unless ivar[0..0] == '@'
|
126
|
+
begin
|
127
|
+
klass = Module.const_get(ivar[1..-1].capitalize)
|
128
|
+
context = node(klass)
|
129
|
+
rescue NameError
|
130
|
+
return nil
|
131
|
+
end
|
132
|
+
{:class => context.klass, :method => context.name}
|
133
|
+
end
|
134
|
+
|
135
|
+
def safe_method_from(context, signature)
|
136
|
+
if context.respond_to?(:safe_method_type)
|
137
|
+
context.safe_method_type(signature)
|
138
|
+
else
|
139
|
+
::RubyLess::SafeClass.safe_method_type_for(context, signature)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
end # RubyLess
|
144
|
+
end # Process
|
145
|
+
end # Zafu
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'zafu/compiler'
|
2
|
+
|
3
|
+
module Zafu
|
4
|
+
class Template
|
5
|
+
def initialize(template, src_helper = nil, compiler = Zafu::Compiler)
|
6
|
+
if template.kind_of?(String)
|
7
|
+
@ast = compiler.new(template)
|
8
|
+
else
|
9
|
+
@ast = compiler.new_with_url(template.path, :helper => src_helper)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_erb(context = {})
|
14
|
+
@ast.to_erb(context)
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_ruby(context = {})
|
18
|
+
src = ::ERB.new("<% __in_erb_template=true %>#{to_erb(context)}", nil, '-').src
|
19
|
+
|
20
|
+
# Ruby 1.9 prepends an encoding to the source. However this is
|
21
|
+
# useless because you can only set an encoding on the first line
|
22
|
+
RUBY_VERSION >= '1.9' ? src.sub(/\A#coding:.*\n/, '') : src
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'zafu/template'
|
2
|
+
|
3
|
+
module Zafu
|
4
|
+
module TestHelper
|
5
|
+
include ::RubyLess::SafeClass
|
6
|
+
|
7
|
+
def zafu_erb(source, src_helper = self, compiler = Zafu::Compiler)
|
8
|
+
Zafu::Template.new(source, src_helper, compiler).to_erb(compilation_context)
|
9
|
+
end
|
10
|
+
|
11
|
+
def zafu_render(source, src_helper = self, compiler = Zafu::Compiler)
|
12
|
+
eval Zafu::Template.new(source, src_helper, compiler).to_ruby(compilation_context)
|
13
|
+
end
|
14
|
+
|
15
|
+
def compilation_context
|
16
|
+
{:node => @node_context, :helper => self}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/zafu.rb
ADDED
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'zafu' #File.join(File.dirname(__FILE__), '..', 'lib', 'zafu')
|
data/script/console
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# File: script/console
|
3
|
+
irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
|
4
|
+
|
5
|
+
libs = " -r irb/completion"
|
6
|
+
# Perhaps use a console_lib to store any extra methods I may want available in the cosole
|
7
|
+
# libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
|
8
|
+
libs << " -r #{File.dirname(__FILE__) + '/../lib/zafu.rb'}"
|
9
|
+
puts "Loading zafu gem"
|
10
|
+
exec "#{irb} #{libs} --simple-prompt"
|
data/script/destroy
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/destroy'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Destroy.new.run(ARGV)
|
data/script/generate
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/generate'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Generate.new.run(ARGV)
|
data/test/markup_test.rb
ADDED
@@ -0,0 +1,232 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class String
|
4
|
+
def blank?
|
5
|
+
self == ''
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
class NodeContextTest < Test::Unit::TestCase
|
10
|
+
include RubyLess::SafeClass
|
11
|
+
safe_method :day => {:class => String, :method => %q{Time.now.strftime('%A')}}
|
12
|
+
Markup = Zafu::Markup
|
13
|
+
|
14
|
+
context 'Parsing parameters' do
|
15
|
+
should 'retrieve values escaped with single quotes' do
|
16
|
+
h = {:class => 'worker', :style => 'tired'}
|
17
|
+
assert_equal h, Markup.parse_params("class='worker' style='tired'")
|
18
|
+
end
|
19
|
+
|
20
|
+
should 'retrieve values escaped with double quotes' do
|
21
|
+
h = {:class => 'worker', :style => 'tired'}
|
22
|
+
assert_equal h, Markup.parse_params('class="worker" style="tired"')
|
23
|
+
end
|
24
|
+
|
25
|
+
should 'retrieve values escaped with mixed quotes' do
|
26
|
+
h = {:class => 'worker', :style => 'tired'}
|
27
|
+
assert_equal h, Markup.parse_params('class=\'worker\' style="tired"')
|
28
|
+
end
|
29
|
+
|
30
|
+
should 'properly handle escaped single quotes' do
|
31
|
+
h = {:class => "that's nice", :style => 'tired'}
|
32
|
+
assert_equal h, Markup.parse_params("class='that\\\'s nice' style='tired'")
|
33
|
+
end
|
34
|
+
|
35
|
+
should 'properly handle escaped double quotes' do
|
36
|
+
h = {:class => '30"', :style => 'tired'}
|
37
|
+
assert_equal h, Markup.parse_params('class="30\\"" style="tired"')
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'Setting parameters' do
|
42
|
+
setup do
|
43
|
+
@markup = Markup.new('p')
|
44
|
+
end
|
45
|
+
|
46
|
+
should 'parse params if the parameters are provided as a string' do
|
47
|
+
@markup.params = "class='shiny' id='slogan'"
|
48
|
+
h = {:class => 'shiny', :id => 'slogan'}
|
49
|
+
assert_equal h, @markup.params
|
50
|
+
end
|
51
|
+
|
52
|
+
should 'set params if the parameters are provided as a hash' do
|
53
|
+
@markup.params = {:class => 'shiny', :style => 'good'}
|
54
|
+
h = {:class => 'shiny', :style => 'good'}
|
55
|
+
assert_equal h, @markup.params
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'Stealing html params' do
|
60
|
+
setup do
|
61
|
+
@markup = Markup.new('p')
|
62
|
+
end
|
63
|
+
|
64
|
+
should 'remove common html params' do
|
65
|
+
base = {:class => 'blue', :name => 'sprout', :id => 'front_cover', :style => 'padding:5px;', :attr => 'title'}
|
66
|
+
@markup.steal_html_params_from(base)
|
67
|
+
new_base = {:name => 'sprout', :attr => 'title'}
|
68
|
+
markup_params = {:class => 'blue', :id => 'front_cover', :style => 'padding:5px;'}
|
69
|
+
assert_equal new_base, base
|
70
|
+
assert_equal markup_params, @markup.params
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'Defining the dom id' do
|
75
|
+
setup do
|
76
|
+
@markup = Markup.new('p')
|
77
|
+
@markup.params[:id] = 'foobar'
|
78
|
+
@markup.dyn_params[:id] = 'foobar'
|
79
|
+
@markup.set_id('<%= @node.zip %>')
|
80
|
+
end
|
81
|
+
|
82
|
+
should 'remove any predifined id' do
|
83
|
+
assert_nil @markup.params[:id]
|
84
|
+
end
|
85
|
+
|
86
|
+
should 'write id in the dynamic params' do
|
87
|
+
assert_equal '<%= @node.zip %>', @markup.dyn_params[:id]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context 'Setting a dynamic param' do
|
92
|
+
setup do
|
93
|
+
@markup = Markup.new('p')
|
94
|
+
@markup.params[:foo] = 'one'
|
95
|
+
@markup.set_dyn_params(:foo => '<%= @node.two %>')
|
96
|
+
end
|
97
|
+
|
98
|
+
should 'clear a static param with same key' do
|
99
|
+
assert_nil @markup.params[:foo]
|
100
|
+
assert_equal '<%= @node.two %>', @markup.dyn_params[:foo]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
context 'Setting a static param' do
|
105
|
+
setup do
|
106
|
+
@markup = Markup.new('p')
|
107
|
+
@markup.dyn_params[:foo] = '<%= @node.two %>'
|
108
|
+
@markup.set_params(:foo => 'one')
|
109
|
+
end
|
110
|
+
|
111
|
+
should 'clear a dynamic param with same key' do
|
112
|
+
assert_nil @markup.dyn_params[:foo]
|
113
|
+
assert_equal 'one', @markup.params[:foo]
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
context 'Appending a static param' do
|
119
|
+
context 'on a static param' do
|
120
|
+
setup do
|
121
|
+
@markup = Markup.new('p')
|
122
|
+
@markup.set_params(:class => 'simple')
|
123
|
+
end
|
124
|
+
|
125
|
+
should 'append param in the static params' do
|
126
|
+
@markup.append_param(:class, 'mind')
|
127
|
+
assert_equal 'simple mind', @markup.params[:class]
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context 'on a dynamic param' do
|
132
|
+
setup do
|
133
|
+
@markup = Markup.new('p')
|
134
|
+
@markup.set_dyn_params(:class => '<%= @foo %>')
|
135
|
+
end
|
136
|
+
|
137
|
+
should 'append param in the dynamic params' do
|
138
|
+
@markup.append_param(:class, 'bar')
|
139
|
+
assert_equal '<%= @foo %> bar', @markup.dyn_params[:class]
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
context 'on an empty param' do
|
144
|
+
setup do
|
145
|
+
@markup = Markup.new('p')
|
146
|
+
end
|
147
|
+
|
148
|
+
should 'set param in the static params' do
|
149
|
+
@markup.append_param(:class, 'bar')
|
150
|
+
assert_equal 'bar', @markup.params[:class]
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
context 'Appending a dynamic param' do
|
156
|
+
context 'on a static param' do
|
157
|
+
setup do
|
158
|
+
@markup = Markup.new('p')
|
159
|
+
@markup.set_params(:class => 'simple')
|
160
|
+
end
|
161
|
+
|
162
|
+
should 'copy the static param in the dynamic params' do
|
163
|
+
@markup.append_dyn_param(:class, '<%= @mind %>')
|
164
|
+
assert_equal 'simple <%= @mind %>', @markup.dyn_params[:class]
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
context 'on a dynamic param' do
|
169
|
+
setup do
|
170
|
+
@markup = Markup.new('p')
|
171
|
+
@markup.set_dyn_params(:class => '<%= @foo %>')
|
172
|
+
end
|
173
|
+
|
174
|
+
should 'append param in the dynamic params' do
|
175
|
+
@markup.append_dyn_param(:class, '<%= @bar %>')
|
176
|
+
assert_equal '<%= @foo %> <%= @bar %>', @markup.dyn_params[:class]
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
context 'on an empty param' do
|
181
|
+
setup do
|
182
|
+
@markup = Markup.new('p')
|
183
|
+
end
|
184
|
+
|
185
|
+
should 'set param in the dynamic params' do
|
186
|
+
@markup.append_dyn_param(:class, '<%= @bar %>')
|
187
|
+
assert_equal '<%= @bar %>', @markup.dyn_params[:class]
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
context 'Wrapping some text' do
|
193
|
+
setup do
|
194
|
+
@text = 'Alice: It would be so nice if something made sense for a change.'
|
195
|
+
@markup = Markup.new('p')
|
196
|
+
@markup.params = {:class => 'quote', :style => 'padding:3px; border:1px solid red;'}
|
197
|
+
end
|
198
|
+
|
199
|
+
should 'add the markup tag around the text' do
|
200
|
+
assert_equal "<p class='quote' style='padding:3px; border:1px solid red;'>#{@text}</p>", @markup.wrap(@text)
|
201
|
+
end
|
202
|
+
|
203
|
+
should 'not wrap twice if called twice' do
|
204
|
+
assert_equal "<p class='quote' style='padding:3px; border:1px solid red;'>#{@text}</p>", @markup.wrap(@markup.wrap(@text))
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
context 'Compiling params' do
|
209
|
+
setup do
|
210
|
+
@markup = Markup.new('p')
|
211
|
+
@markup.params = %q{class='one #{day}' id='foobar' name='#{day}'}
|
212
|
+
end
|
213
|
+
|
214
|
+
context 'with compile_params' do
|
215
|
+
setup do
|
216
|
+
@markup.compile_params(self)
|
217
|
+
end
|
218
|
+
|
219
|
+
should 'translate dynamic params into ERB by using RubyLess' do
|
220
|
+
assert_equal %q{<%= "one #{Time.now.strftime('%A')}" %>}, @markup.dyn_params[:class]
|
221
|
+
end
|
222
|
+
|
223
|
+
should 'translate without string on single dynamic content' do
|
224
|
+
assert_equal %q{<%= Time.now.strftime('%A') %>}, @markup.dyn_params[:name]
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
|
231
|
+
|
232
|
+
|
data/test/mock/params.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module Mock
|
2
|
+
module Params
|
3
|
+
def self.included(base)
|
4
|
+
base.before_process :filter_params
|
5
|
+
end
|
6
|
+
|
7
|
+
def filter_params
|
8
|
+
if klass = @params.delete(:class)
|
9
|
+
if klass =~ /#\{/
|
10
|
+
res = RubyLess.translate("\"#{klass}\"", self)
|
11
|
+
@markup.append_dyn_param(:class, "<%= #{res} %>")
|
12
|
+
else
|
13
|
+
@markup.append_param(:class, klass)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,190 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class NodeContextTest < Test::Unit::TestCase
|
4
|
+
class Page;end
|
5
|
+
class SubPage < Page; end
|
6
|
+
class Comment;end
|
7
|
+
NodeContext = Zafu::NodeContext
|
8
|
+
|
9
|
+
context 'In a blank context' do
|
10
|
+
setup do
|
11
|
+
@context = NodeContext.new('@node', Page)
|
12
|
+
end
|
13
|
+
|
14
|
+
should 'return the current name' do
|
15
|
+
assert_equal '@node', @context.name
|
16
|
+
end
|
17
|
+
|
18
|
+
should 'return the current class' do
|
19
|
+
assert_equal Page, @context.klass
|
20
|
+
end
|
21
|
+
|
22
|
+
should 'return true on will_be with the same class' do
|
23
|
+
assert @context.will_be?(Page)
|
24
|
+
end
|
25
|
+
|
26
|
+
should 'return false on will_be with a sub class' do
|
27
|
+
assert !@context.will_be?(SubPage)
|
28
|
+
end
|
29
|
+
|
30
|
+
should 'return false on will_be with a different class' do
|
31
|
+
assert !@context.will_be?(String)
|
32
|
+
end
|
33
|
+
|
34
|
+
should 'return self on a get for the same class' do
|
35
|
+
assert_equal @context.object_id, @context.get(Page).object_id
|
36
|
+
end
|
37
|
+
|
38
|
+
should 'return nil on a get for another class' do
|
39
|
+
assert_nil @context.get(Comment)
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'with a sub-class' do
|
43
|
+
setup do
|
44
|
+
@context = NodeContext.new('@node', SubPage)
|
45
|
+
end
|
46
|
+
|
47
|
+
should 'return true on will_be with the same class' do
|
48
|
+
assert @context.will_be?(SubPage)
|
49
|
+
end
|
50
|
+
|
51
|
+
should 'return true on will_be with a super class' do
|
52
|
+
assert @context.will_be?(Page)
|
53
|
+
end
|
54
|
+
|
55
|
+
should 'return false on will_be with a different class' do
|
56
|
+
assert !@context.will_be?(String)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'In a sub-context' do
|
62
|
+
setup do
|
63
|
+
@parent = NodeContext.new('@node', Page)
|
64
|
+
@context = @parent.move_to('comment1', Comment)
|
65
|
+
end
|
66
|
+
|
67
|
+
should 'return the current name' do
|
68
|
+
assert_equal 'comment1', @context.name
|
69
|
+
end
|
70
|
+
|
71
|
+
should 'return the current class' do
|
72
|
+
assert_equal Comment, @context.klass
|
73
|
+
end
|
74
|
+
|
75
|
+
should 'return self on a get for the same class' do
|
76
|
+
assert_equal @context.object_id, @context.get(Comment).object_id
|
77
|
+
end
|
78
|
+
|
79
|
+
should 'return the parent on a get for the class of the parent' do
|
80
|
+
assert_equal @parent.object_id, @context.get(Page).object_id
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context 'In a deeply nested context' do
|
85
|
+
setup do
|
86
|
+
@grandgrandma = NodeContext.new('@comment', Comment)
|
87
|
+
@grandma = @grandgrandma.move_to('page', Page)
|
88
|
+
@mother = @grandma.move_to('comment1', Comment)
|
89
|
+
@context = @mother.move_to('var1', String)
|
90
|
+
end
|
91
|
+
|
92
|
+
should 'return the current name' do
|
93
|
+
assert_equal 'var1', @context.name
|
94
|
+
end
|
95
|
+
|
96
|
+
should 'return the current class' do
|
97
|
+
assert_equal String, @context.klass
|
98
|
+
end
|
99
|
+
|
100
|
+
should 'return the first ancestor matching class on get' do
|
101
|
+
assert_equal @mother.object_id, @context.get(Comment).object_id
|
102
|
+
end
|
103
|
+
|
104
|
+
should 'return nil if no ancestor matches class on get' do
|
105
|
+
assert_nil @context.get(Fixnum)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context 'In a sub-classes context' do
|
110
|
+
setup do
|
111
|
+
@context = NodeContext.new('super', SubPage)
|
112
|
+
end
|
113
|
+
|
114
|
+
should 'find the current context required class is an ancestor' do
|
115
|
+
assert_equal @context.object_id, @context.get(Page).object_id
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
context 'In a list context' do
|
120
|
+
setup do
|
121
|
+
@context = NodeContext.new('list', [Page])
|
122
|
+
end
|
123
|
+
|
124
|
+
should 'find the context and resolve with first' do
|
125
|
+
assert context = @context.get(Page)
|
126
|
+
assert_equal 'list.first', context.name
|
127
|
+
assert_equal Page, context.klass
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context 'Generating a dom id' do
|
132
|
+
context 'in a blank context' do
|
133
|
+
setup do
|
134
|
+
@context = NodeContext.new('@foo', Page)
|
135
|
+
end
|
136
|
+
|
137
|
+
should 'return the node name in DOM id' do
|
138
|
+
assert_equal '<%= @foo.zip %>', @context.dom_id
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
context 'in a hierarchy of contexts' do
|
143
|
+
setup do
|
144
|
+
@a = NodeContext.new('@node', Page)
|
145
|
+
@b = NodeContext.new('var1', [Page], @a)
|
146
|
+
@c = NodeContext.new('var2', Page, @b)
|
147
|
+
@context = NodeContext.new('var3', Page, @c)
|
148
|
+
end
|
149
|
+
|
150
|
+
context 'with parents as dom_scopes' do
|
151
|
+
setup do
|
152
|
+
@b.dom_scope!
|
153
|
+
@c.dom_scope!
|
154
|
+
end
|
155
|
+
|
156
|
+
should 'use dom_scopes' do
|
157
|
+
assert_equal '<%= var1.zip %>_<%= var2.zip %>_<%= var3.zip %>', @context.dom_id
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
context 'with ancestors and self as dom_scopes' do
|
162
|
+
setup do
|
163
|
+
@a.dom_scope!
|
164
|
+
@context.dom_scope!
|
165
|
+
end
|
166
|
+
|
167
|
+
should 'not use self twice' do
|
168
|
+
assert_equal '<%= @node.zip %>_<%= var3.zip %>', @context.dom_id
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
context 'with a parent defining a dom_prefix' do
|
173
|
+
setup do
|
174
|
+
@b.dom_prefix = 'cart'
|
175
|
+
end
|
176
|
+
|
177
|
+
should 'use dom_prefix' do
|
178
|
+
assert_equal 'cart_<%= var3.zip %>', @context.dom_id
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
|
187
|
+
|
188
|
+
|
189
|
+
|
190
|
+
|