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 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