attrtastic 0.2.2 → 0.3.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/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