attrtastic 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/attrtastic.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require "attrtastic/semantic_attributes_helper"
2
+ require "attrtastic/semantic_attributes_builder"
1
3
  ##
2
4
  # Attrtastic, in its assumption, should be similar to formtastic and
3
5
  # ease displaying AR informations, help create scaffolded show and index
@@ -5,394 +7,5 @@
5
7
  #
6
8
  # @author Boruta Mirosław
7
9
  module Attrtastic
8
-
9
- class SemanticAttributesBuilder
10
-
11
- # Only for testing purposes
12
- attr_reader :record, :template
13
-
14
- def initialize(record, template)
15
- @record, @template = record, template
16
- end
17
-
18
- ##
19
- # Creates block of attributes with optional header. Attributes are surrounded with ordered list.
20
- #
21
- # @overload attributes(options = {}, &block)
22
- # Creates attributes list without header, yields block to include each attribute
23
- #
24
- # @param [Hash] options Options for formating attributes block
25
- # @option options [String] :name (nil) Optional header of attributes section
26
- # @option options [String] :class ('') Name of html class to add to attributes block
27
- # @option options [String] :header_class ('') Name of html class to add to header
28
- # @yield Block which can call #attribute to include attribute value
29
- #
30
- # @example
31
- # <% attr.attributes do %>
32
- # <%= attr.attribute :name %>
33
- # <%= attr.attribute :email %>
34
- # <% end %>
35
- #
36
- # @example
37
- # <% attr.attributes :name => "User" do %>
38
- # <%= attr.attribute :name %>
39
- # <%= attr.attribute :email %>
40
- # <% end %>
41
- #
42
- # @example
43
- # <% attr.attributes :for => :user do |user| %>
44
- # <%= user.attribute :name %>
45
- # <%= user.attribute :email %>
46
- # <% user.attribute :profile do %>
47
- # <%= link_to h(user.record.name), user_path(user.record) %>
48
- # <% end %>
49
- # <% end %>
50
- #
51
- # @example
52
- # <% attr.attributes :for => @user do |user| %>
53
- # <%= user.attribute :name %>
54
- # <%= user.attribute :email %>
55
- # <% user.attribute :profile do %>
56
- # <%= link_to h(@user.name), user_path(@user) %>
57
- # <% end %>
58
- # <% end %>
59
- #
60
- # @example
61
- # <% attr.attributes :for => :posts do |post| %>
62
- # <%= post.attribute :author %>
63
- # <%= post.attribute :title %>
64
- # <% end %>
65
- #
66
- # @example
67
- # <% attr.attributes :for => @posts do |post| %>
68
- # <%= post.attribute :author %>
69
- # <%= post.attribute :title %>
70
- # <% end %>
71
- #
72
- # @overload attributes(header, options = {}, &block)
73
- # Creates attributes list with header and yields block to include each attribute
74
- #
75
- # @param [String] header Header of attributes section
76
- # @param [Hash] options Options for formating attributes block
77
- # @option options [String] :class ('') Name of html class to add to attributes block
78
- # @option options [String] :header_class ('') Name of html class to add to header
79
- # @option optinos [Symbol,Object] :for Optional new record for new builder
80
- # passed as argument block. This new record can be symbol of method name for actual
81
- # record, or any other object which is passed as new record for builder.
82
- # @yield Block which can call #attribute to include attribute value
83
- # @yieldparam builder Builder instance holding actual record (retivable via #record)
84
- #
85
- # @example
86
- # <% attr.attributes "User info" do %>
87
- # <%= attr.attribute :name" %>
88
- # <%= attr.attribute :email %>
89
- # <% end %>
90
- #
91
- # @example
92
- # <% attr.attributes "User", :for => :user do |user| %>
93
- # <%= user.attribute :name %>
94
- # <%= user.attribute :email %>
95
- # <% user.attribute :profile do %>
96
- # <%= link_to h(user.record.name), user_path(user.record) %>
97
- # <% end %>
98
- # <% end %>
99
- #
100
- # @example
101
- # <% attr.attributes "User", :for => @user do |user| %>
102
- # <%= user.attribute :name %>
103
- # <%= user.attribute :email %>
104
- # <% user.attribute :profile do %>
105
- # <%= link_to h(@user.name), user_path(@user) %>
106
- # <% end %>
107
- # <% end %>
108
- #
109
- # @example
110
- # <% attr.attributes "Post", :for => :posts do |post| %>
111
- # <%= post.attribute :author %>
112
- # <%= post.attribute :title %>
113
- # <% end %>
114
- #
115
- # @example
116
- # <% attr.attributes "Post", :for => @posts do |post| %>
117
- # <%= post.attribute :author %>
118
- # <%= post.attribute :title %>
119
- # <% end %>
120
- #
121
- # @overload attributes(*symbols, options = {})
122
- # Creates attributes list without header, attributes are given as list of symbols (record properties)
123
- #
124
- # @param [Symbol, ...] symbols List of attributes
125
- # @param [Hash] options Options for formating attributes block
126
- # @option options [String] :name (nil) Optional header of attributes section
127
- # @option options [String] :class ('') Name of html class to add to attributes block
128
- # @option options [String] :header_class ('') Name of html class to add to header
129
- #
130
- # @example
131
- # <% attr.attributes :name, :email %>
132
- #
133
- # @example
134
- # <% attr.attributes :name, :email, :for => :author %>
135
- #
136
- # @example
137
- # <% attr.attributes :name, :email, :for => @user %>
138
- #
139
- # @example
140
- # <% attr.attributes :title, :for => :posts %>
141
- #
142
- # @example
143
- # <% attr.attributes :title, :for => @posts %>
144
- #
145
- # @overload attributes(header, *symbols, options = {})
146
- # Creates attributes list with header, attributes are given as list of symbols (record properties)
147
- #
148
- # @param [String] header Header of attributes section
149
- # @param [Symbol, ...] symbols Optional list of attributes
150
- # @param [Hash] options Options for formating attributes block
151
- # @option options [String] :class ('') Name of html class to add to attributes block
152
- # @option options [String] :header_class ('') Name of html class to add to header
153
- #
154
- # @example
155
- # <% attr.attributes "User info" :name, :email %>
156
- #
157
- # @example
158
- # <% attr.attributes "Author", :name, :email, :for => :author %>
159
- #
160
- # @example
161
- # <% attr.attributes "Author", :name, :email, :for => @user %>
162
- #
163
- # @example
164
- # <% attr.attributes "Post", :title, :for => :posts %>
165
- #
166
- # @example
167
- # <% attr.attributes "Post", :title, :for => @posts %>
168
- #
169
- # @example All together
170
- # <% attr.attributes "User info", :name, :email, :class => "user_info", :header_class => "header important" %>
171
- #
172
- # @example With block
173
- # <% attr.attributes "User info" :class => "user_info", :header_class => "header important" do %>
174
- # <%= attr.attribute :name %>
175
- # <%= attr.attribute :email %>
176
- # <% end %>
177
- #
178
- # @see #attribute
179
- def attributes(*args, &block)
180
- options = {}
181
- if args.last and args.last.kind_of? Hash
182
- options = args.last
183
- args = args[0 .. -2]
184
- end
185
- options[:html] ||= {}
186
-
187
- if args.first and args.first.is_a? String
188
- options[:name] = args.shift
189
- end
190
-
191
- if options[:for].blank?
192
- attributes_for(record, args, options, &block)
193
- else
194
- if options[:for].is_a? Symbol
195
- for_value = record.send(options[:for])
196
- else
197
- for_value = options[:for]
198
- end
199
-
200
- [*for_value].each do |value|
201
- value_options = options.clone
202
- value_options[:html][:class] = [ options[:html][:class], value.class.to_s.underscore ].compact.join(" ")
203
-
204
- attributes_for(value, args, options, &block)
205
- end
206
- end
207
-
208
- end
209
-
210
- ##
211
- # Creates list entry for single record attribute
212
- #
213
- # @overload attribute(method, options = {})
214
- # Creates entry for record attribute
215
- #
216
- # @param [Symbol] method Attribute name of given record
217
- # @param [Hash] options Options
218
- # @option options [Hash] :html ({}) Hash with optional :class, :label_class and :value_class names of class for html
219
- # @option options [String] :label Label for attribute entry, overrides default label name from symbol
220
- # @option options [String] :value Value of attribute entry, overrides default value from record
221
- # @option options [Boolean] :display_empty (false) Indicates if print value of given attribute even if it is blank?
222
- #
223
- # @example
224
- # <%= attr.attribute :name %>
225
- #
226
- # @example
227
- # <%= attr.attribute :name, :label => "Full user name" %>
228
- #
229
- # @example
230
- # <%= attr.attribute :name, :value => @user.full_name %>
231
- #
232
- # @overload attribute(method, options = {}, &block)
233
- # Creates entry for attribute given with block
234
- #
235
- # @param [Symbol] method Attribute name of given record
236
- # @param [Hash] options Options
237
- # @option options [Hash] :html ({}) Hash with optional :class, :label_class and :value_class names of classes for html
238
- # @option options [String] :label Label for attribute entry, overrides default label name from symbol
239
- # @yield Block which is executed in place of value for attribute
240
- #
241
- # @example
242
- # <% attr.attribute :name do %>
243
- # <%= link_to @user.full_name, user_path(@user) %>
244
- #
245
- # @overload attribute(options = {}, &block)
246
- # Creates entry for attribute with given block, options[:label] is mandatory in this case.
247
- #
248
- # @param [:Hash] options Options
249
- # @option options [Hash] :html ({}) Hash with optional :class, :label_class and :value_class names of classes for html
250
- # @option options [String] :label Mandatory label for attribute entry
251
- # @yield Block which is executed in place of value for attribute
252
- #
253
- # @example
254
- # <% attr.attribute :label => "User link" do %>
255
- # <%= link_to @user.full_name, user_path(@user) %>
256
- #
257
- # @example
258
- # <%= attr.attribute :name, :display_empty => true %>
259
- #
260
- # @example
261
- # <% attr.attribute :label => "User link" do %>
262
- # <%= link_to @user.full_name, user_path(@user) %>
263
- #
264
- def attribute(*args, &block)
265
- options = {}
266
- if args.last and args.last.kind_of? Hash
267
- options = args.last
268
- args = args[0 .. -2]
269
- end
270
- options[:html] ||= {}
271
-
272
- method = args.shift
273
-
274
- html_label_class = [ "label", options[:html][:label_class] ].compact.join(" ")
275
- html_value_class = [ "value", options[:html][:value_class] ].compact.join(" ")
276
- html_class = [ "attribute", options[:html][:class] ].compact.join(" ")
277
-
278
- label = options.key?(:label) ? options[:label] : label_for_attribute(method)
279
- label_content = template.content_tag(:span, label, :class => html_label_class)
280
-
281
- unless block_given?
282
- value = options.key?(:value) ? options[:value] : value_of_attribute(method)
283
- value_content = template.content_tag(:span, value, :class => html_value_class)
284
-
285
- if value.present? or options[:display_empty]
286
- content = [ label_content, value_content ].join
287
- template.content_tag(:li, content, :class => html_class)
288
- end
289
- else
290
- template.concat(template.tag(:li, {:class => html_class}, true))
291
- template.concat(label_content)
292
- template.concat(template.tag(:span, {:class => html_value_class}, true))
293
- yield
294
- template.concat("</span>")
295
- template.concat("</li>")
296
- end
297
- end
298
-
299
- private
300
-
301
- def attributes_for(object, methods, options, &block)
302
- new_builder = self.class.new(object, template)
303
-
304
- html_class = [ "attributes", options[:html].delete(:class) ].compact.join(" ")
305
- html_header_class = [ "legend", options[:html].delete(:header_class) ].compact.join(" ")
306
-
307
- template.concat(template.tag(:div, {:class => html_class}, true))
308
-
309
- header = options[:name]
310
-
311
- if header.present?
312
- template.concat(template.content_tag(:div, header, :class => html_header_class))
313
- end
314
-
315
- if block_given?
316
- template.concat(template.tag(:ol, {}, true))
317
- yield(new_builder)
318
- template.concat("</ol>")
319
- elsif methods.present?
320
- template.concat(template.tag(:ol, {}, true))
321
- attrs = methods.map {|method| new_builder.attribute(method, options)}.compact.join
322
- template.concat(attrs)
323
- template.concat("</ol>")
324
- end
325
-
326
- template.concat("</div>")
327
- end
328
-
329
- def label_for_attribute(method)
330
- if record.class.respond_to?(:human_attribute_name)
331
- record.class.human_attribute_name(method.to_s)
332
- else
333
- method.to_s.send(:humanize)
334
- end
335
- end
336
-
337
- def value_of_attribute(method)
338
- value = record.send(method)
339
- value_methods = [ :to_label, :display_name, :full_name, :name, :title, :username, :login, :value ]
340
- value_method = value_methods.find { |m| value.respond_to?(m) } || :to_s
341
- value.send(value_method)
342
- end
343
-
344
- end
345
-
346
- ##
347
- # Helper which should be included in ActionView. Adds #semantic_attributes_for
348
- # method, which helps printing attributes for given record, similar to
349
- # formtastic's sematnic_form_for
350
- #
351
- # @example
352
- # ActionView::Base.send :include, Attrtastic::SemanticAttributesHelper
353
- #
354
- # @example Example of useage
355
- # <% semantic_attributes_for @user do |attr| %>
356
- # <% attr.attributes "User info" do %>
357
- # <%= attr.attribute :name %>
358
- # <%= attr.attribute :email %>
359
- # <% end %>
360
- # <% attr.attributes "User details" do %>
361
- # <%= attr.attribute :weight %>
362
- # <%= attr.attribute :height %>
363
- # <%= attr.attribute :age %>
364
- # <% end %>
365
- # <% end %>
366
- module SemanticAttributesHelper
367
-
368
- ##
369
- # Creates attributes for given object
370
- #
371
- # @param[ActiveRecord] record AR instance record for which to display attributes
372
- # @param[Hash] options Opions
373
- # @option options [Hash] :html ({}) Hash with optional :class html class name for html block
374
- # @yield [attr] Block which is yield inside of markup
375
- # @yieldparam [SemanticAttributesBuilder] builder Builder for attributes for given AR record
376
- #
377
- # @example
378
- # <% semantic_attributes_for @user do |attr| %>
379
- # <% attr.attributes do %>
380
- # <%= attr.attribute :name %>
381
- # <%= attr.attribute :email %>
382
- # <% end %>
383
- # <% end %>
384
- #
385
- def semantic_attributes_for(record, options = {}, &block)
386
- options[:html] ||= {}
387
-
388
- html_class = [ "attrtastic", record.class.to_s.underscore, options[:html][:class] ].compact.join(" ")
389
-
390
- concat(tag(:div, { :class => html_class}, true))
391
- yield SemanticAttributesBuilder.new(record, self) if block_given?
392
- concat("</div>")
393
- end
394
-
395
- end
396
-
397
10
  end
398
11
 
data/rails/init.rb CHANGED
@@ -1,2 +1 @@
1
- require File.join(File.dirname(__FILE__), *%w[.. lib attrtastic])
2
- ActionView::Base.send :include, Attrtastic::SemanticAttributesHelper
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "init"))
data/test/helper.rb CHANGED
@@ -6,7 +6,7 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
6
6
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
7
7
  require 'attrtastic'
8
8
 
9
- class Test::Unit::TestCase
9
+ class TestCase < Test::Unit::TestCase
10
10
  def html(string)
11
11
  string.split(/\n/m).map(&:strip).join
12
12
  end
@@ -22,7 +22,7 @@ class Test::Unit::TestCase
22
22
  ]
23
23
 
24
24
  ActionView::Base.send :include, Attrtastic::SemanticAttributesHelper
25
- @template = ActionView::Base.new.tap{ |av| av.output_buffer = "" }
25
+ @template = ActionView::Base.new.tap{ |av| av.output_buffer = ActiveSupport::SafeBuffer.new }
26
26
  @user_builder = Attrtastic::SemanticAttributesBuilder.new(@user, @template)
27
27
  @blog_builder = Attrtastic::SemanticAttributesBuilder.new(@blog, @template)
28
28
  end
@@ -1,6 +1,6 @@
1
1
  require 'helper'
2
2
 
3
- class TestAttribute < Test::Unit::TestCase
3
+ class TestAttribute < TestCase
4
4
 
5
5
  context "attribute" do
6
6
 
@@ -113,13 +113,12 @@ class TestAttribute < Test::Unit::TestCase
113
113
  </li>
114
114
  EOHTML
115
115
 
116
- @user_builder.attribute :full_name do
116
+ actual = @user_builder.attribute :full_name do
117
117
  @user_builder.template.output_buffer << "John Doe"
118
118
  3.times do
119
119
  @user_builder.template.output_buffer << "!"
120
120
  end
121
121
  end
122
- actual = @template.output_buffer.to_s
123
122
  assert_equal expected, actual
124
123
  end
125
124
 
@@ -131,13 +130,12 @@ class TestAttribute < Test::Unit::TestCase
131
130
  </li>
132
131
  EOHTML
133
132
 
134
- @user_builder.attribute :label => "Full name" do
133
+ actual = @user_builder.attribute :label => "Full name" do
135
134
  @user_builder.template.output_buffer << "John Doe"
136
135
  3.times do
137
136
  @user_builder.template.output_buffer << "!"
138
137
  end
139
138
  end
140
- actual = @template.output_buffer.to_s
141
139
  assert_equal expected, actual
142
140
  end
143
141