zafu 0.5.0 → 0.6.0
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/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
|