zafu 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +11 -0
- data/Rakefile +2 -1
- data/lib/zafu/all.rb +6 -4
- data/lib/zafu/controller_methods.rb +27 -18
- data/lib/zafu/info.rb +1 -1
- data/lib/zafu/markup.rb +87 -25
- data/lib/zafu/node_context.rb +48 -4
- data/lib/zafu/ordered_hash.rb +47 -0
- data/lib/zafu/parser.rb +140 -55
- data/lib/zafu/parsing_rules.rb +49 -17
- data/lib/zafu/process/ajax.rb +344 -66
- data/lib/zafu/process/conditional.rb +36 -25
- data/lib/zafu/process/context.rb +101 -4
- data/lib/zafu/process/forms.rb +124 -0
- data/lib/zafu/process/html.rb +78 -83
- data/lib/zafu/process/ruby_less_processing.rb +248 -0
- data/lib/zafu/test_helper.rb +1 -1
- data/lib/zafu/view_methods.rb +6 -0
- data/test/markup_test.rb +150 -8
- data/test/mock/classes.rb +24 -0
- data/test/mock/core_ext.rb +9 -0
- data/test/mock/params.rb +4 -10
- data/test/mock/process.rb +7 -0
- data/test/mock/test_compiler.rb +9 -0
- data/test/node_context_test.rb +135 -46
- data/test/ordered_hash_test.rb +69 -0
- data/test/ruby_less_test.rb +29 -19
- data/test/test_helper.rb +4 -3
- data/test/zafu/ajax.yml +7 -0
- data/test/zafu/asset.yml +3 -0
- data/test/zafu/basic.yml +3 -0
- data/test/zafu/markup.yml +4 -0
- data/test/zafu/meta.yml +8 -0
- data/test/zafu/security.yml +19 -0
- data/test/zafu_test.rb +29 -12
- data/zafu.gemspec +28 -6
- metadata +41 -8
- data/lib/zafu/process/ruby_less.rb +0 -145
data/History.txt
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
== 0.6.0 2010-05-27
|
2
|
+
|
3
|
+
* 3 major enhancements
|
4
|
+
* Added rubyless_class_scope to filter evaluation on class type.
|
5
|
+
* Started to move tests from Zena.
|
6
|
+
* Added 'up(klass)' method.
|
7
|
+
|
8
|
+
* 1 minor enhancement
|
9
|
+
* Added 'has_param' to the Markup object.
|
10
|
+
* Added 'prepend_param'.
|
11
|
+
|
1
12
|
== 0.5.0 2010-03-21
|
2
13
|
|
3
14
|
* 6 major enhancement
|
data/Rakefile
CHANGED
@@ -13,7 +13,8 @@ begin
|
|
13
13
|
gem.homepage = "http://zenadmin.org/zafu"
|
14
14
|
gem.authors = ["Gaspard Bucher"]
|
15
15
|
gem.add_development_dependency "shoulda", ">= 0"
|
16
|
-
gem.
|
16
|
+
gem.add_development_dependency "yamltest", ">= 0.5.0"
|
17
|
+
gem.add_dependency "rubyless", ">= 0.5.0"
|
17
18
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
18
19
|
end
|
19
20
|
Jeweler::GemcutterTasks.new
|
data/lib/zafu/all.rb
CHANGED
@@ -1,17 +1,19 @@
|
|
1
1
|
require 'zafu/parsing_rules'
|
2
|
-
|
2
|
+
require 'zafu/process/ajax'
|
3
3
|
require 'zafu/process/html'
|
4
|
-
require 'zafu/process/
|
4
|
+
require 'zafu/process/ruby_less_processing'
|
5
5
|
require 'zafu/process/context'
|
6
6
|
require 'zafu/process/conditional'
|
7
|
+
require 'zafu/process/forms'
|
7
8
|
|
8
9
|
module Zafu
|
9
10
|
All = [
|
10
11
|
Zafu::ParsingRules,
|
11
|
-
# Zafu::Process::Ajax,
|
12
12
|
Zafu::Process::HTML,
|
13
13
|
Zafu::Process::Context,
|
14
14
|
Zafu::Process::Conditional,
|
15
|
-
Zafu::Process::
|
15
|
+
Zafu::Process::RubyLessProcessing,
|
16
|
+
Zafu::Process::Ajax,
|
17
|
+
Zafu::Process::Forms,
|
16
18
|
]
|
17
19
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Zafu
|
2
2
|
module ControllerMethods
|
3
3
|
def self.included(base)
|
4
|
-
base.
|
4
|
+
base.helper Common
|
5
5
|
if RAILS_ENV == 'development'
|
6
6
|
base.class_eval do
|
7
7
|
def render_for_file_with_rebuild(template_path, status = nil, layout = nil, locals = {}) #:nodoc:
|
@@ -24,26 +24,35 @@ module Zafu
|
|
24
24
|
zafu_context[:node] = Zafu::NodeContext.new(name, klass)
|
25
25
|
end
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
27
|
+
module Common
|
28
|
+
def zafu_context
|
29
|
+
@zafu_context ||= {}
|
30
|
+
end
|
30
31
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
32
|
+
# Quote for html attributes (field quote). There might be a better rails alternative to this.
|
33
|
+
def fquote(text)
|
34
|
+
text.to_s.gsub("'",''')
|
35
|
+
end
|
36
|
+
|
37
|
+
# This method should return the template for a given 'src' and
|
38
|
+
# 'base_path'.
|
39
|
+
def get_template_text(path, base_path)
|
40
|
+
[path, "#{base_path}/#{path}"].each do |p|
|
41
|
+
begin
|
42
|
+
t = self.view_paths.find_template(p, 'html') # FIXME: format ?
|
43
|
+
rescue ActionView::MissingTemplate
|
44
|
+
t = nil
|
45
|
+
end
|
46
|
+
return [t.source, t.path, t.base_path] if t
|
39
47
|
end
|
40
|
-
|
48
|
+
nil
|
41
49
|
end
|
42
|
-
nil
|
43
|
-
end
|
44
50
|
|
45
|
-
|
46
|
-
|
47
|
-
|
51
|
+
def template_url_for_asset(opts)
|
52
|
+
opts[:src]
|
53
|
+
end
|
54
|
+
end # Common
|
55
|
+
|
56
|
+
include Common
|
48
57
|
end
|
49
58
|
end
|
data/lib/zafu/info.rb
CHANGED
data/lib/zafu/markup.rb
CHANGED
@@ -1,9 +1,15 @@
|
|
1
|
+
require 'zafu/ordered_hash'
|
2
|
+
|
1
3
|
module Zafu
|
2
4
|
# A Markup object is used to hold information on the tag used (<li>), it's parameters (.. class='xxx') and
|
3
5
|
# indentation.
|
4
6
|
class Markup
|
5
|
-
EMPTY_TAGS = %w{meta input}
|
6
|
-
STEAL_PARAMS =
|
7
|
+
EMPTY_TAGS = %w{meta input link}
|
8
|
+
STEAL_PARAMS = {
|
9
|
+
'link' => [:href, :charset, :rel, :type, :media, :rev, :target],
|
10
|
+
'script' => [:type, :charset, :defer],
|
11
|
+
:other => [:class, :id, :style],
|
12
|
+
}
|
7
13
|
|
8
14
|
# Tag used ("li" for example). The tag can be nil (no tag).
|
9
15
|
attr_accessor :tag
|
@@ -23,9 +29,9 @@ module Zafu
|
|
23
29
|
# Parse parameters into a hash. This parsing supports multiple values for one key by creating additional keys:
|
24
30
|
# <tag do='hello' or='goodbye' or='gotohell'> creates the hash {:do=>'hello', :or=>'goodbye', :or1=>'gotohell'}
|
25
31
|
def parse_params(text)
|
26
|
-
return
|
32
|
+
return OrderedHash.new unless text
|
27
33
|
return text if text.kind_of?(Hash)
|
28
|
-
params =
|
34
|
+
params = OrderedHash.new
|
29
35
|
rest = text.strip
|
30
36
|
while (rest != '')
|
31
37
|
if rest =~ /(.+?)=/
|
@@ -60,8 +66,8 @@ module Zafu
|
|
60
66
|
def initialize(tag)
|
61
67
|
@done = false
|
62
68
|
@tag = tag
|
63
|
-
@params =
|
64
|
-
@dyn_params =
|
69
|
+
@params = OrderedHash.new
|
70
|
+
@dyn_params = OrderedHash.new
|
65
71
|
end
|
66
72
|
|
67
73
|
# Set params either using a string (like "alt='time passes' class='zen'")
|
@@ -73,11 +79,15 @@ module Zafu
|
|
73
79
|
end
|
74
80
|
end
|
75
81
|
|
82
|
+
# Another way to set dynamic params (the argument must be a hash).
|
83
|
+
def dyn_params=(h)
|
84
|
+
set_dyn_params(h)
|
85
|
+
end
|
86
|
+
|
76
87
|
# Steal html parameters from an existing hash (the stolen parameters are removed
|
77
88
|
# from the argument)
|
78
89
|
def steal_html_params_from(p)
|
79
|
-
|
80
|
-
STEAL_PARAMS.each do |k|
|
90
|
+
steal_keys.each do |k|
|
81
91
|
next unless p[k]
|
82
92
|
@params[k] = p.delete(k)
|
83
93
|
end
|
@@ -100,18 +110,38 @@ module Zafu
|
|
100
110
|
|
101
111
|
# Set dynamic html parameters.
|
102
112
|
def set_dyn_params(hash)
|
103
|
-
hash.
|
104
|
-
|
113
|
+
hash.each do |k,v|
|
114
|
+
set_dyn_param(k, v)
|
105
115
|
end
|
106
|
-
|
116
|
+
end
|
117
|
+
|
118
|
+
# Set dynamic html parameters.
|
119
|
+
def set_dyn_param(key, value)
|
120
|
+
@params.delete(key)
|
121
|
+
@dyn_params[key] = value
|
107
122
|
end
|
108
123
|
|
109
124
|
# Set static html parameters.
|
110
125
|
def set_params(hash)
|
111
|
-
hash.
|
112
|
-
|
126
|
+
hash.each do |k,v|
|
127
|
+
set_param(k, v)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# Set static html parameters.
|
132
|
+
def set_param(key, value)
|
133
|
+
@dyn_params.delete(key)
|
134
|
+
@params[key] = value
|
135
|
+
end
|
136
|
+
|
137
|
+
def prepend_param(key, value)
|
138
|
+
if prev_value = @dyn_params[key]
|
139
|
+
@dyn_params[key] = "#{value} #{prev_value}"
|
140
|
+
elsif prev_value = @params[key]
|
141
|
+
@params[key] = "#{value} #{prev_value}"
|
142
|
+
else
|
143
|
+
@params[key] = value
|
113
144
|
end
|
114
|
-
@params.merge!(hash)
|
115
145
|
end
|
116
146
|
|
117
147
|
def append_param(key, value)
|
@@ -124,11 +154,23 @@ module Zafu
|
|
124
154
|
end
|
125
155
|
end
|
126
156
|
|
127
|
-
def
|
157
|
+
def prepend_dyn_param(key, value, conditional = false)
|
158
|
+
spacer = conditional ? '' : ' '
|
128
159
|
if prev_value = @params.delete(key)
|
129
|
-
@dyn_params[key] = "#{
|
160
|
+
@dyn_params[key] = "#{value}#{spacer}#{prev_value}"
|
130
161
|
elsif prev_value = @dyn_params[key]
|
131
|
-
@dyn_params[key] = "#{
|
162
|
+
@dyn_params[key] = "#{value}#{spacer}#{prev_value}"
|
163
|
+
else
|
164
|
+
@dyn_params[key] = value
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def append_dyn_param(key, value, conditional = false)
|
169
|
+
spacer = conditional ? '' : ' '
|
170
|
+
if prev_value = @params.delete(key)
|
171
|
+
@dyn_params[key] = "#{prev_value}#{spacer}#{value}"
|
172
|
+
elsif prev_value = @dyn_params[key]
|
173
|
+
@dyn_params[key] = "#{prev_value}#{spacer}#{value}"
|
132
174
|
else
|
133
175
|
@dyn_params[key] = value
|
134
176
|
end
|
@@ -140,10 +182,27 @@ module Zafu
|
|
140
182
|
dyn_params[:id] = erb_id
|
141
183
|
end
|
142
184
|
|
185
|
+
# Return true if the given key exists in params or dyn_params.
|
186
|
+
def has_param?(key)
|
187
|
+
params[key] || dyn_params[key]
|
188
|
+
end
|
189
|
+
|
190
|
+
# Duplicate markup and make sure params and dyn_params are duplicated as well.
|
191
|
+
def dup
|
192
|
+
markup = Markup.new(@tag)
|
193
|
+
markup.params = @params.dup
|
194
|
+
markup.dyn_params = @dyn_params.dup
|
195
|
+
markup
|
196
|
+
end
|
197
|
+
|
143
198
|
# Wrap the given text with our tag. If 'append' is not empty, append the text
|
144
199
|
# after the tag parameters: <li class='foo'[APPEND HERE]>text</li>.
|
145
200
|
def wrap(text, *append)
|
146
201
|
return text if @done
|
202
|
+
if dyn_params[:id]
|
203
|
+
@tag ||= 'div'
|
204
|
+
end
|
205
|
+
|
147
206
|
append ||= []
|
148
207
|
if @tag
|
149
208
|
if text.blank? && EMPTY_TAGS.include?(@tag)
|
@@ -159,15 +218,14 @@ module Zafu
|
|
159
218
|
(@space_before || '') + res + (@space_after || '')
|
160
219
|
end
|
161
220
|
|
221
|
+
def steal_keys
|
222
|
+
(STEAL_PARAMS[@tag] || []) + STEAL_PARAMS[:other]
|
223
|
+
end
|
224
|
+
|
162
225
|
private
|
163
226
|
def params_to_html
|
164
227
|
para = []
|
165
|
-
keys =
|
166
|
-
|
167
|
-
@dyn_params.each do |k,v|
|
168
|
-
keys << k
|
169
|
-
para << " #{k}='#{v}'"
|
170
|
-
end
|
228
|
+
keys = @dyn_params.keys
|
171
229
|
|
172
230
|
@params.each do |k,v|
|
173
231
|
next if keys.include?(k)
|
@@ -179,8 +237,12 @@ module Zafu
|
|
179
237
|
end
|
180
238
|
end
|
181
239
|
|
182
|
-
|
183
|
-
|
240
|
+
@dyn_params.each do |k,v|
|
241
|
+
para << " #{k}='#{v}'"
|
242
|
+
end
|
243
|
+
|
244
|
+
para
|
184
245
|
end
|
246
|
+
|
185
247
|
end
|
186
248
|
end
|
data/lib/zafu/node_context.rb
CHANGED
@@ -3,6 +3,9 @@ module Zafu
|
|
3
3
|
# The name of the variable halding the current object or list ("@node", "var1")
|
4
4
|
attr_reader :name
|
5
5
|
|
6
|
+
# The previous NodeContext
|
7
|
+
attr_reader :up
|
8
|
+
|
6
9
|
# The type of object contained in the current context (Node, Page, Image)
|
7
10
|
attr_reader :klass
|
8
11
|
|
@@ -27,16 +30,31 @@ module Zafu
|
|
27
30
|
# Return true if the NodeContext represents an element of the given type. We use 'will_be' because
|
28
31
|
# it is equivalent to 'is_a', but for future objects (during rendering).
|
29
32
|
def will_be?(type)
|
30
|
-
klass.ancestors.include?(type)
|
33
|
+
klass.kind_of?(Array) ? klass.first.ancestors.include?(type) : klass.ancestors.include?(type)
|
31
34
|
end
|
32
35
|
|
33
36
|
# Return a new node context that corresponds to the current object when rendered alone (in an ajax response or
|
34
37
|
# from a direct 'show' in a controller). The returned node context has no parent (up is nil).
|
35
38
|
# The convention is to use the class of the current object to build this name.
|
36
|
-
|
39
|
+
# You can also use an 'after_class' parameter to move up in the current object's class hierarchy (see #master_class).
|
40
|
+
def as_main(after_class = nil)
|
41
|
+
klass = after_class ? master_class(after_class) : self.klass
|
37
42
|
NodeContext.new("@#{klass.to_s.underscore}", klass)
|
38
43
|
end
|
39
44
|
|
45
|
+
# Find the class just afer 'after_class' in the class hierarchy.
|
46
|
+
# For example if we have Dog < Mamal < Animal < Creature,
|
47
|
+
# master_class(Creature) would return Animal
|
48
|
+
def master_class(after_class)
|
49
|
+
klass = self.klass
|
50
|
+
klass = klass.first if klass.kind_of?(Array)
|
51
|
+
begin
|
52
|
+
up = klass.superclass
|
53
|
+
return klass if up == after_class
|
54
|
+
end while klass = up
|
55
|
+
return self.klass
|
56
|
+
end
|
57
|
+
|
40
58
|
# Generate a unique DOM id for this element based on dom_scopes defined in parent contexts.
|
41
59
|
def dom_id
|
42
60
|
@dom_id ||= begin
|
@@ -49,7 +67,7 @@ module Zafu
|
|
49
67
|
end
|
50
68
|
|
51
69
|
# This holds the current context's unique name if it has it's own or one from the hierarchy. If
|
52
|
-
# none is found, it builds one
|
70
|
+
# none is found, it builds one.
|
53
71
|
def dom_prefix
|
54
72
|
@dom_prefix || (@up ? @up.dom_prefix : nil)
|
55
73
|
end
|
@@ -62,7 +80,7 @@ module Zafu
|
|
62
80
|
|
63
81
|
def get(klass)
|
64
82
|
if list_context?
|
65
|
-
if self.klass.first
|
83
|
+
if klass <= self.klass.first
|
66
84
|
NodeContext.new("#{self.name}.first", self.klass.first)
|
67
85
|
elsif @up
|
68
86
|
@up.get(klass)
|
@@ -78,10 +96,36 @@ module Zafu
|
|
78
96
|
end
|
79
97
|
end
|
80
98
|
|
99
|
+
def up(klass = nil)
|
100
|
+
klass ? @up.get(klass) : @up
|
101
|
+
end
|
102
|
+
|
103
|
+
# Return true if the current klass is an Array.
|
81
104
|
def list_context?
|
82
105
|
klass.kind_of?(Array)
|
83
106
|
end
|
84
107
|
|
108
|
+
# Return the name of the current class with underscores like 'sub_page'.
|
109
|
+
def underscore
|
110
|
+
class_name.to_s.underscore
|
111
|
+
end
|
112
|
+
|
113
|
+
# Return the class name or the superclass name if the current class is an anonymous class.
|
114
|
+
# FIXME: just use klass.to_s (so that we can do clever things with 'to_s')
|
115
|
+
def class_name
|
116
|
+
if list_context?
|
117
|
+
klass = @klass.first
|
118
|
+
"[#{(klass.name.blank? ? klass.superclass : klass).name}]"
|
119
|
+
else
|
120
|
+
(@klass.name.blank? ? @klass.superclass : @klass).name
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# Return the name to use for input fields
|
125
|
+
def form_name
|
126
|
+
@form_name ||= master_class(ActiveRecord::Base).name.underscore
|
127
|
+
end
|
128
|
+
|
85
129
|
protected
|
86
130
|
# List of scopes defined in ancestry (used to generate dom_id).
|
87
131
|
def dom_scopes
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Zafu
|
2
|
+
|
3
|
+
if RUBY_VERSION.split('.')[0..1].join('.').to_f > 1.8
|
4
|
+
OrderedHash = Hash
|
5
|
+
else
|
6
|
+
class OrderedHash < Hash
|
7
|
+
|
8
|
+
def []=(k, v)
|
9
|
+
get_keys << k unless get_keys.include?(k)
|
10
|
+
super
|
11
|
+
end
|
12
|
+
|
13
|
+
def merge!(hash)
|
14
|
+
hash.keys.each do |k|
|
15
|
+
get_keys << k unless get_keys.include?(k)
|
16
|
+
end
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
alias o_keys keys
|
21
|
+
def get_keys
|
22
|
+
@keys ||= o_keys
|
23
|
+
end
|
24
|
+
|
25
|
+
def keys
|
26
|
+
get_keys.dup
|
27
|
+
end
|
28
|
+
|
29
|
+
def each
|
30
|
+
keys.each do |k|
|
31
|
+
yield(k, self[k])
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def delete(k)
|
36
|
+
get_keys.delete(k)
|
37
|
+
super
|
38
|
+
end
|
39
|
+
|
40
|
+
def dup
|
41
|
+
copy = super
|
42
|
+
copy.instance_variable_set(:@keys, keys)
|
43
|
+
copy
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|