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 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.add_dependency "rubyless", ">= 0.4.0"
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
- # require 'zafu/process/ajax'
2
+ require 'zafu/process/ajax'
3
3
  require 'zafu/process/html'
4
- require 'zafu/process/ruby_less'
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::RubyLess
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.helper_method :zafu_context, :get_template_text, :template_url_for_asset
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
- def zafu_context
28
- @zafu_context ||= {}
29
- end
27
+ module Common
28
+ def zafu_context
29
+ @zafu_context ||= {}
30
+ end
30
31
 
31
- # This method should return the template for a given 'src' and
32
- # 'base_path'.
33
- def get_template_text(path, base_path)
34
- [path, "#{base_path}/#{path}"].each do |p|
35
- begin
36
- t = self.view_paths.find_template(p, 'html') # FIXME: format ?
37
- rescue ActionView::MissingTemplate
38
- t = nil
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
- return [t.source, t.path, t.base_path] if t
48
+ nil
41
49
  end
42
- nil
43
- end
44
50
 
45
- def template_url_for_asset(opts)
46
- opts[:src]
47
- end
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
@@ -1,4 +1,4 @@
1
1
  module Zafu
2
- VERSION = '0.5.0'
2
+ VERSION = '0.6.0'
3
3
  end
4
4
 
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 = [:class, :id, :style]
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 {} unless text
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
- @params ||= {}
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.keys.each do |k|
104
- @params.delete(k)
113
+ hash.each do |k,v|
114
+ set_dyn_param(k, v)
105
115
  end
106
- @dyn_params.merge!(hash)
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.keys.each do |k|
112
- @dyn_params.delete(k)
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 append_dyn_param(key, value)
157
+ def prepend_dyn_param(key, value, conditional = false)
158
+ spacer = conditional ? '' : ' '
128
159
  if prev_value = @params.delete(key)
129
- @dyn_params[key] = "#{prev_value} #{value}"
160
+ @dyn_params[key] = "#{value}#{spacer}#{prev_value}"
130
161
  elsif prev_value = @dyn_params[key]
131
- @dyn_params[key] = "#{prev_value} #{value}"
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
- # we sort so that the output is always the same (needed for testing)
183
- para.sort.join('')
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
@@ -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
- def as_main
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... How ?
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.ancestors.include?(klass)
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