view 1.0.0.alpha.1 → 1.0.0.alpha.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/README.rdoc +29 -44
  2. data/lib/view/formatter.rb +126 -35
  3. data/lib/view/formatters/array.rb +32 -0
  4. data/lib/view/formatters/auto.rb +47 -24
  5. data/lib/view/formatters/blank.rb +20 -0
  6. data/lib/view/formatters/boolean.rb +17 -1
  7. data/lib/view/formatters/currency.rb +1 -1
  8. data/lib/view/formatters/date.rb +3 -2
  9. data/lib/view/formatters/datetime.rb +3 -2
  10. data/lib/view/formatters/delimited.rb +1 -1
  11. data/lib/view/formatters/file_link.rb +1 -1
  12. data/lib/view/formatters/guess.rb +18 -0
  13. data/lib/view/formatters/html_safe.rb +2 -1
  14. data/lib/view/formatters/human.rb +1 -1
  15. data/lib/view/formatters/image.rb +1 -1
  16. data/lib/view/formatters/link.rb +1 -1
  17. data/lib/view/formatters/percentage.rb +1 -1
  18. data/lib/view/formatters/phone.rb +1 -1
  19. data/lib/view/formatters/precision.rb +1 -1
  20. data/lib/view/formatters/self.rb +4 -1
  21. data/lib/view/formatters/sentence.rb +18 -23
  22. data/lib/view/formatters/size.rb +1 -1
  23. data/lib/view/helper.rb +1 -1
  24. data/lib/view/version.rb +1 -1
  25. data/lib/view.rb +81 -13
  26. data/spec/view/formatter_spec.rb +13 -0
  27. data/spec/view/formatters/auto_spec.rb +13 -16
  28. data/spec/view/formatters/blank_spec.rb +23 -0
  29. data/spec/view/formatters/boolean_spec.rb +6 -6
  30. data/spec/view/formatters/date_spec.rb +3 -3
  31. data/spec/view/formatters/datetime_spec.rb +2 -2
  32. data/spec/view/formatters/guess_spec.rb +25 -0
  33. data/spec/view/formatters/self_spec.rb +1 -1
  34. data/spec/view/formatters/sentence_spec.rb +17 -1
  35. metadata +28 -10
  36. data/lib/view/formatters/nil.rb +0 -11
  37. data/spec/view/formatters/nil_spec.rb +0 -15
  38. data/spec/view/view_spec.rb +0 -13
data/README.rdoc CHANGED
@@ -1,5 +1,7 @@
1
1
  = View
2
2
 
3
+ {Source}[http://github.com/iain/view] | {Documentation}[http://rubydoc.info/github/iain/view/master/frames]
4
+
3
5
  Automatic viewer. Very configurable. Very flexible. Very alpha (for now).
4
6
 
5
7
  It is made for displaying stuff in views. This can be very handy for DSLs that create views.
@@ -11,7 +13,7 @@ But first, the view!
11
13
 
12
14
  Use it from your views:
13
15
 
14
- = view @post
16
+ <%= view @post %>
15
17
 
16
18
  View will try to figure out what the most logical way is to present the object you passed in.
17
19
  If the @post object has a title for instance, it will use that.
@@ -20,7 +22,7 @@ See the auto formatter for more information.
20
22
 
21
23
  You can use view anywhere you like:
22
24
 
23
- puts View.to_s(@post)
25
+ puts View.format(@post)
24
26
 
25
27
  But beware that for many formatters, a reference to the template is required.
26
28
  It is a helper for the view part of your application after all.
@@ -29,55 +31,56 @@ It is a helper for the view part of your application after all.
29
31
 
30
32
  View will automatically try to choose the proper formatter. You can specify a formatter yourself:
31
33
 
32
- = view @post.created_at, :as => :date
34
+ <%= view @post.created_at, :as => :date %>
33
35
 
34
36
  You can add a block to specify your own behavior. The parsed value is passed in as a block-variable.
35
37
 
36
- = view @post.author do |author|
37
- = link_to author, @post.author
38
+ <%= view @post.author do |author| %>
39
+ <%= link_to author, @post.author %>
40
+ <% end %>
38
41
 
39
42
  Most formatters pass their options down to the method they use, such as the image formatter:
40
43
 
41
- = view @user.avatar, :as => :image, :size => "40x40", :class => "avatar"
44
+ <%= view @user.avatar, :as => :image, :size => "40x40", :class => "avatar" %>
42
45
 
43
46
  == Examples
44
47
 
45
48
  There are many formatters included (18 and counting), but here are some interesting use cases of some of them.
46
49
 
47
50
  # Options are passed to the helper methods:
48
- = view @post, :as => :link, :method => :delete, :confirm => "are you sure?"
51
+ view @post, :as => :link, :method => :delete, :confirm => "are you sure?"
49
52
 
50
53
  # Renders a link to the edit_page of the post:
51
- = view @post, :as => :link, :path => [ :edit ]
54
+ view @post, :as => :link, :path => [ :edit ]
52
55
 
53
56
  # Renders a sentence of links:
54
- = view Post.all, :each => { :as => :link }
57
+ view Post.all, :each => { :as => :link }
55
58
 
56
59
  # When using paperclip, renders the image:
57
- = view @project.logo, :as => :image
60
+ view @project.logo, :as => :image
58
61
 
59
62
  # Renders "yes" or "no" (with I18n support!)
60
- = view @user.admin?
63
+ view @user.admin?
61
64
 
62
65
  See the formatters in lib/views/formatters to see their full documentation.
63
66
 
64
67
  == Adding formatters
65
68
 
66
- You can add a formatter by inheriting from View::Formatter.
67
- The only method you need to implement is the to_s method.
69
+ You can add a formatter by inheriting from +View::Formatter+.
70
+ The only method you need to implement is the +format+ method.
68
71
 
69
72
  In the class you have access to the following methods:
70
73
 
71
- * value: the object passed in
72
- * options: a filtered hash of options
73
- * all_options: the unfiltered hash
74
- * template: call methods like link_to on this
74
+ * +value+: the object passed in
75
+ * +options+: a filtered hash of options
76
+ * +all_options+: the unfiltered hash
77
+ * +template+: call methods like link_to on this
75
78
 
76
79
  If you wanted a uppercase formatter for example, you could do this:
77
80
 
78
81
  class Uppercase < View::Formatter
79
82
 
80
- def to_s
83
+ def format
81
84
  value.to_s.upcase
82
85
  end
83
86
 
@@ -85,7 +88,7 @@ If you wanted a uppercase formatter for example, you could do this:
85
88
 
86
89
  The name of the formatter is automatically infered from the name of the class.
87
90
 
88
- You can use the .as method to specify a different name.
91
+ You can use the +.as+ method to specify a different name.
89
92
 
90
93
  class Foo < View::Formatter
91
94
  as :bar
@@ -99,20 +102,20 @@ You can control which options are allowed, by adding reserved options:
99
102
  end
100
103
 
101
104
  Now, the options method will return the options passed by the user, minus foo and bar.
102
- To use them, in your code, use the all_options method.
105
+ To use them, in your code, use the +all_options+ method.
103
106
  This is done to easily pass the options to another method, without cluttering:
104
107
 
105
108
  class Paragraph < View::Formatter
106
- def to_s
109
+ def format
107
110
  template.content_tag(:p, value.to_s, options)
108
111
  end
109
112
  end
110
113
 
111
- To more tightly control which options are allowed, specify the allowed_options.
114
+ To more tightly control which options are allowed, specify the allowed options:
112
115
 
113
116
  class Size < View::Formatter
114
117
  self.allowed_options = [ :separator, :delimiter, :precision ]
115
- def to_s
118
+ def format
116
119
  template.number_to_human_size(value, options)
117
120
  end
118
121
  end
@@ -121,33 +124,15 @@ You can use the existing formatters as examples.
121
124
 
122
125
  == Configuration:
123
126
 
124
- See lib/view.rb for information on configuration.
127
+ See +lib/view.rb+ for information on configuration.
125
128
 
126
129
  == Installation
127
130
 
128
- === Rails 3
129
-
130
- In Rails 3, just add it to your Gemfile:
131
+ Just add it to your Gemfile:
131
132
 
132
133
  gem 'view'
133
134
 
134
- Run <tt>bundle install</tt> and you're ready to go!
135
-
136
- === Rails 2
137
-
138
- In Rails 2, add it to app/environment.rb:
139
-
140
- config.gem 'view'
141
-
142
- And run <tt>rake gems:install</tt> to get it.
143
-
144
- Afterwards, include the helper mehtod manually, by editing app/helpers/application_helper.rb:
145
-
146
- module ApplicationHelper
147
- include View::Helper
148
- end
149
-
150
- Caution: some helpers may use new helper methods from Rails 3 and might not work in Rails 2.
135
+ Run +bundle install+ and you're ready to go!
151
136
 
152
137
  == Contributing
153
138
 
@@ -1,5 +1,6 @@
1
1
  module View
2
2
 
3
+ # @abstract Subclass and override {#format} to implement your own formatter.
3
4
  class Formatter
4
5
 
5
6
  attr_reader :value, :template, :block
@@ -13,58 +14,150 @@ module View
13
14
  class_inheritable_array :allowed_options
14
15
  self.allowed_options = []
15
16
 
16
- def initialize(value, options = {}, template = nil, &block)
17
- @value = value
18
- @options = options
19
- @template = template
20
- @block = block
21
- end
22
-
17
+ # When you inherit from View::Formatter, the formatters goes on the list,
18
+ # but in reverse order, so that newer formatters kan override older ones.
23
19
  def self.inherited(formatter)
24
20
  super
25
21
  formatters.unshift(formatter)
26
22
  end
27
23
 
28
- def self.formatters
29
- View.formatters ||= []
30
- end
31
-
24
+ # Specify your own name for the formatter. By default the name of the class
25
+ # will be used (without any namespacing), but you can override it yourself
26
+ # by calling this method.
27
+ #
28
+ # @example
29
+ # class SomeStrangeName < View::Formatter
30
+ # as :real_name
31
+ # end
32
+ #
33
+ # View.format @foo, :as => :real_name
34
+ #
35
+ # @param [Symbol] type The new name of the formatter
32
36
  def self.as(type)
33
37
  @type = type
34
38
  end
35
39
 
40
+ # @return [String] the type of the formatter, either set via +.as+ or
41
+ # automatically deducted from the class name.
42
+ #
43
+ # @see .as
36
44
  def self.type
37
45
  @type || name.split('::').last.underscore
38
46
  end
39
47
 
40
- def self.to_s(*args, &block)
41
- new(*args, &block).format
42
- end
43
-
48
+ # By default, blank values (nil, empty strings, etc), will override any
49
+ # formatter you specified. This way empty values are handled globally.
50
+ #
51
+ # If you don't want this, you can either turn it off per formatter.
52
+ # Call this method to turn it off.
53
+ #
54
+ # @example
55
+ # class IHandleMyOwnBlank < View::Formatter
56
+ # skip_blank_formatter
57
+ # # etc...
58
+ # end
59
+ #
60
+ # @see View::Blank
61
+ def self.skip_blank_formatter
62
+ @skip_blank_formatter = true
63
+ end
64
+
65
+ # If you didn't specify a format instance method inside specific
66
+ # formatters, this will raise an error.
67
+ #
68
+ # @abstract Subclass and override {#format} to implement your own formatter.
69
+ # @return [String] the formatted value
44
70
  def format
45
- if block
46
- captured_value
47
- else
48
- formatted_value
49
- end
50
- end
51
-
52
- def to_s
53
71
  msg <<-MSG.squeeze(' ')
54
- The only thing a formatter needs to do is implement the #to_s method.
72
+ The only thing a formatter needs to do is implement the #format method.
55
73
  If you see this error, you forgot to do that for the #{self.class.type} formatter.
56
74
  MSG
57
75
  raise NotImplementedError.new(msg)
58
76
  end
59
77
 
78
+ # The "safe" options that you can toss around to helper methods.
79
+ #
80
+ # You can specify which methods are "safe" by white listing or black
81
+ # listing. White listing takes precedence over black listing.
82
+ #
83
+ # To access options that are filtered out, use +all_options+.
84
+ # It's generally a good idea to black list options that you use inside your
85
+ # formatter.
86
+ #
87
+ # The options +:as+ and +:block_arguments+ are black listed by default.
88
+ #
89
+ # @example White listing:
90
+ #
91
+ # class Sentence < View::Formatter
92
+ # self.allowed_options = [ :words_connector, :last_word_connector ]
93
+ #
94
+ # def format
95
+ # value.to_sentence(options)
96
+ # end
97
+ # end
98
+ #
99
+ # @example Black listing:
100
+ #
101
+ # class Link < View::Formatter
102
+ # self.reserved_options = [ :to ]
103
+ #
104
+ # def format
105
+ # template.link_to(value.to_s, all_options[:to], options)
106
+ # end
107
+ # end
108
+ #
109
+ # @return [Hash] filtered options
110
+ # @see #all_options
60
111
  def options
61
112
  default_options.merge(all_options).delete_if do |key, value|
62
113
  option_not_allowed?(key)
63
114
  end
64
115
  end
65
116
 
117
+ # This calls the format action. You can override it to do something with
118
+ # the formatted value. This doesn't (and shouldn't) do any formatting
119
+ # itself.
120
+ #
121
+ # @see #format
122
+ def to_s
123
+ format
124
+ end
125
+
126
+ # @return All options, unfiltered.
127
+ # @see #options
128
+ def all_options
129
+ @options
130
+ end
131
+
66
132
  private
67
133
 
134
+ def self.skip_blank_formatter?
135
+ @skip_blank_formatter
136
+ end
137
+
138
+ def self.format(*args, &block)
139
+ new(*args, &block).send(:format!)
140
+ end
141
+
142
+ def format!
143
+ if block
144
+ captured_value
145
+ else
146
+ formatted_value
147
+ end
148
+ end
149
+
150
+ def self.formatters
151
+ View.formatters ||= []
152
+ end
153
+
154
+ def initialize(value, options = {}, template = nil, &block)
155
+ @value = value
156
+ @options = options
157
+ @template = template
158
+ @block = block
159
+ end
160
+
68
161
  def template_can_capture?
69
162
  template && template.respond_to?(:capture)
70
163
  end
@@ -78,31 +171,29 @@ module View
78
171
  end
79
172
 
80
173
  def captured_value_by_template
81
- template.capture(formatted_value, *block_arguments, &block)
174
+ template.capture(*block_arguments, &block)
82
175
  end
83
176
 
84
177
  def captured_return_value
85
- block.call(formatted_value, *block_arguments)
178
+ block.call(*block_arguments)
86
179
  end
87
180
 
88
181
  def formatted_value
182
+ formatter_not_found unless formatter
89
183
  formatter.new(value, all_options, template, &block).to_s
90
184
  end
91
185
 
92
186
  def formatter
93
- find_formatter || formatter_not_found
187
+ blank_formatter || find_formatter
94
188
  end
95
189
 
96
190
  def formatter_not_found
191
+ formatter_names = self.class.formatters.map { |formatter| formatter.type.to_s }
97
192
  raise "Couldn't find the #{as} formatter. Got: #{formatter_names.join(', ')}"
98
193
  end
99
194
 
100
- def formatter_names
101
- self.class.formatters.map { |formatter| formatter.type.to_s }
102
- end
103
-
104
195
  def find_formatter
105
- self.class.formatters.find { |formatter| formatter.type.to_s == as.to_s }
196
+ @formatter ||= self.class.formatters.find { |formatter| formatter.type.to_s == as.to_s }
106
197
  end
107
198
 
108
199
  def option_not_allowed?(key)
@@ -114,15 +205,15 @@ module View
114
205
  end
115
206
 
116
207
  def block_arguments
117
- all_options[:block_arguments] || []
208
+ all_options[:block_arguments] || [ formatted_value ]
118
209
  end
119
210
 
120
211
  def as
121
212
  all_options[:as] || View.default_formatter
122
213
  end
123
214
 
124
- def all_options
125
- @options
215
+ def blank_formatter
216
+ Blank if !find_formatter.skip_blank_formatter? && value.blank?
126
217
  end
127
218
 
128
219
  end
@@ -0,0 +1,32 @@
1
+ module View
2
+
3
+ # @abstract Subclass this for html safe lists with formatted each support.
4
+ class Array < Formatter
5
+
6
+ def to_s
7
+ if all_safe?
8
+ super.html_safe
9
+ else
10
+ super
11
+ end
12
+ end
13
+
14
+ def all_safe?
15
+ formatted_values.all? do |element|
16
+ element.respond_to?(:html_safe?) && element.html_safe?
17
+ end
18
+ end
19
+
20
+ def formatted_values
21
+ @formatted_values ||= value.map do |element|
22
+ View.format(element, each, template, &block)
23
+ end
24
+ end
25
+
26
+ def each
27
+ all_options[:each] || { :as => View.default_formatter }
28
+ end
29
+
30
+ end
31
+
32
+ end
@@ -1,47 +1,70 @@
1
1
  module View
2
2
 
3
+ # The auto formatter tries to figure out what other formatter should be the
4
+ # most appropriate to use and delegates the formatting to that formatter.
5
+ #
6
+ # This is fully configurable too. See Auto.add
3
7
  class Auto < Formatter
4
8
 
5
- def to_s
6
- if as
7
- format
8
- else
9
- guess
10
- end
9
+ skip_blank_formatter
10
+
11
+ # Adds behavior to check which view should automatically be used.
12
+ #
13
+ # @example
14
+ #
15
+ # View::Auto.add :boolean do
16
+ # value == true || value == false
17
+ # end
18
+ #
19
+ # @param [Symbol] formatter_name The name of the formatter
20
+ #
21
+ # @yield The block is eval'd inside the formatter, so you can use the
22
+ # instance methods that are available for every formatters, like +value+
23
+ # and +options+.
24
+ #
25
+ # @yieldreturn [true, false] The first block to evaluate to true will
26
+ # determine the formatter. New blocks are checked first.
27
+ def self.add(formatter_name, &block)
28
+ auto_formatters.unshift(:formatter => formatter_name, :block => block)
11
29
  end
12
30
 
13
- def datetime_format?
14
- value.respond_to?(:strftime)
31
+ private
32
+
33
+ def format
34
+ format!
15
35
  end
16
36
 
17
- def file_link_format?
18
- View.file_methods.any? { |method| value.respond_to?(method) }
37
+ def self.auto_formatters
38
+ @auto_formatters ||= []
19
39
  end
20
40
 
21
- def boolean_format?
22
- value == true || value == false
41
+ def as
42
+ as = self.class.auto_formatters.find { |auto| instance_eval(&auto[:block]) }
43
+ as ? as[:formatter] : :guess
23
44
  end
24
45
 
25
- def nil_format?
26
- value.nil?
46
+ add :datetime do
47
+ value.respond_to?(:strftime)
27
48
  end
28
49
 
29
- def sentence_format?
30
- value.respond_to?(:to_sentence)
50
+ add :file_link do
51
+ View.file_methods.any? { |method| value.respond_to?(method) }
31
52
  end
32
53
 
33
- def link_format?
34
- all_options[:to]
54
+ add View.default_list_formatter do
55
+ value.respond_to?(:each)
35
56
  end
36
57
 
37
- def as
38
- %w|nil boolean file_link datetime sentence link|.find { |type| send("#{type}_format?") }
58
+ add :link do
59
+ all_options.has_key?(:to)
39
60
  end
40
61
 
41
- def guess
42
- View.guessing_methods.each do |method|
43
- return value.send(method) if value.respond_to?(method)
44
- end
62
+ add :blank do
63
+ value.blank?
64
+ end
65
+
66
+ add :boolean do
67
+ value == true || value == false
45
68
  end
46
69
 
47
70
  end
@@ -0,0 +1,20 @@
1
+ module View
2
+
3
+ # The default formatter for blank objects, like nil, empty strings and empty
4
+ # arrays. It will display an empty string or something else, which you can
5
+ # configure with I18n.
6
+ #
7
+ # @example config/locales/en.yml
8
+ # en:
9
+ # view:
10
+ # blank: "nothing"
11
+ #
12
+ class Blank < Formatter
13
+
14
+ def format
15
+ ::I18n.t(:blank, :scope => :view, :default => "").html_safe
16
+ end
17
+
18
+ end
19
+
20
+ end
@@ -1,8 +1,24 @@
1
1
  module View
2
2
 
3
+ # The default formatter for booleans.
4
+ #
5
+ # It will display "Yes" or "No".
6
+ #
7
+ # You can configure it with I18n. When writing 'true' and 'false' as keys in
8
+ # yaml, please don't forget the quotes.
9
+ #
10
+ # @example config/locales/en.yml
11
+ # en:
12
+ # view:
13
+ # booleans:
14
+ # 'true': Yup
15
+ # 'false': Nope
16
+ #
3
17
  class Boolean < Formatter
4
18
 
5
- def to_s
19
+ skip_blank_formatter
20
+
21
+ def format
6
22
  ::I18n.t(boolean_value.to_s, :scope => [:view, :booleans], :default => default)
7
23
  end
8
24
 
@@ -4,7 +4,7 @@ module View
4
4
 
5
5
  self.allowed_options = [ :precision, :unit, :separator, :delimiter, :format ]
6
6
 
7
- def to_s
7
+ def format
8
8
  template.number_to_currency(value, options)
9
9
  end
10
10
 
@@ -1,9 +1,10 @@
1
1
  module View
2
2
 
3
+ # Uses I18n to localize a date.
3
4
  class Date < Formatter
4
5
 
5
- def to_s
6
- ::I18n.l(value.to_date, options) if value.present?
6
+ def format
7
+ ::I18n.l(value.to_date, options)
7
8
  end
8
9
 
9
10
  end
@@ -1,9 +1,10 @@
1
1
  module View
2
2
 
3
+ # Uses I18n to format a datetime object.
3
4
  class Datetime < Formatter
4
5
 
5
- def to_s
6
- ::I18n.l(value, options) if value.present?
6
+ def format
7
+ ::I18n.l(value, options)
7
8
  end
8
9
 
9
10
  end
@@ -4,7 +4,7 @@ module View
4
4
 
5
5
  self.allowed_options = [ :separator, :delimiter ]
6
6
 
7
- def to_s
7
+ def format
8
8
  template.number_with_delimiter(value, options)
9
9
  end
10
10
 
@@ -5,7 +5,7 @@ module View
5
5
  self.reserved_options = [ :text, :text_method ]
6
6
  self.default_options = { :target => "_blank" }
7
7
 
8
- def to_s
8
+ def format
9
9
  template.link_to(text, path, options)
10
10
  end
11
11
 
@@ -0,0 +1,18 @@
1
+ module View
2
+
3
+ # This formatter is the fallback formatter for auto. It figures out which
4
+ # method will be called to get a proper version to render.
5
+ #
6
+ # @see View.guessing_methods
7
+ class Guess < Formatter
8
+
9
+ def format
10
+ View.guessing_methods.each do |method|
11
+ return value.send(method) if value.respond_to?(method)
12
+ end
13
+ value
14
+ end
15
+
16
+ end
17
+
18
+ end
@@ -1,8 +1,9 @@
1
1
  module View
2
2
 
3
+ # This formatter marks the value as html safe
3
4
  class HtmlSafe < Formatter
4
5
 
5
- def to_s
6
+ def format
6
7
  value.to_s.html_safe
7
8
  end
8
9
 
@@ -7,7 +7,7 @@ module View
7
7
  self.allowed_options = [ :locale, :precision, :significant, :separator, :delimiter,
8
8
  :strip_insignificant_zeros, :units, :format ]
9
9
 
10
- def to_s
10
+ def format
11
11
  template.number_to_human(value, options)
12
12
  end
13
13
 
@@ -4,7 +4,7 @@ module View
4
4
 
5
5
  self.reserved_options = [ :with ]
6
6
 
7
- def to_s
7
+ def format
8
8
  template.image_tag(path, options) if file?
9
9
  end
10
10
 
@@ -4,7 +4,7 @@ module View
4
4
 
5
5
  self.reserved_options = [ :to, :path, :text ]
6
6
 
7
- def to_s
7
+ def format
8
8
  template.link_to(format, to, options)
9
9
  end
10
10
 
@@ -4,7 +4,7 @@ module View
4
4
 
5
5
  self.allowed_options = [ :precision, :separator, :delimiter ]
6
6
 
7
- def to_s
7
+ def format
8
8
  template.number_to_percentage(value, options)
9
9
  end
10
10
 
@@ -4,7 +4,7 @@ module View
4
4
 
5
5
  self.allowed_options = [ :area_code, :delimiter, :extension, :country_code ]
6
6
 
7
- def to_s
7
+ def format
8
8
  template.number_to_phone(value, options)
9
9
  end
10
10
 
@@ -4,7 +4,7 @@ module View
4
4
 
5
5
  self.allowed_options = [ :precision, :separator, :delimiter ]
6
6
 
7
- def to_s
7
+ def format
8
8
  template.number_with_precision(value, options)
9
9
  end
10
10
 
@@ -1,8 +1,11 @@
1
1
  module View
2
2
 
3
+ # This formatter just returns itself. It doesn't do anything.
3
4
  class Self < Formatter
4
5
 
5
- def to_s
6
+ skip_blank_formatter
7
+
8
+ def format
6
9
  value
7
10
  end
8
11
 
@@ -1,31 +1,26 @@
1
1
  module View
2
2
 
3
- class Sentence < Formatter
3
+ # This formatter is for arrays and stuff into a sentence.
4
+ #
5
+ # You can pass the options for sentence and, like any other array formatter,
6
+ # you can pass an each option, that contains the options for every element in
7
+ # the array.
8
+ #
9
+ # If you don't pass any options in each, it will autoformat every element.
10
+ #
11
+ # @example
12
+ #
13
+ # View.format @dates, :as => :sentence,
14
+ # :each => { :as => :date, :format => :short }
15
+ #
16
+ # @see View::Array
17
+ # @see http://rubydoc.info/docs/rails/3.0.0/Array:to_sentence
18
+ class Sentence < Array
4
19
 
5
20
  self.allowed_options = [ :words_connector, :two_words_connector, :last_word_connector ]
6
21
 
7
- def to_s
8
- if all_safe?
9
- sentence.html_safe
10
- else
11
- sentence
12
- end
13
- end
14
-
15
- def all_safe?
16
- formatted_values.all? { |element| element.html_safe? }
17
- end
18
-
19
- def formatted_values
20
- value.map { |element| View.to_s(element, each, template, &block) }
21
- end
22
-
23
- def sentence
24
- formatted_values.to_sentence if value.present?
25
- end
26
-
27
- def each
28
- all_options[:each] || { :as => View.default_formatter }
22
+ def format
23
+ formatted_values.to_sentence(options)
29
24
  end
30
25
 
31
26
  end
@@ -4,7 +4,7 @@ module View
4
4
 
5
5
  self.allowed_options = [ :precision, :separator, :delimiter ]
6
6
 
7
- def to_s
7
+ def format
8
8
  template.number_to_human_size(value, options)
9
9
  end
10
10
 
data/lib/view/helper.rb CHANGED
@@ -3,7 +3,7 @@ module View
3
3
  module Helper
4
4
 
5
5
  def view(value, options = {}, &block)
6
- ::View.to_s(value, options, self, &block)
6
+ ::View.format(value, options, self, &block)
7
7
  end
8
8
 
9
9
  end
data/lib/view/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module View
2
- VERSION = '1.0.0.alpha.1'
2
+ VERSION = '1.0.0.alpha.2'
3
3
  end
data/lib/view.rb CHANGED
@@ -4,26 +4,94 @@ module View
4
4
  autoload :Helper, 'view/helper'
5
5
  autoload :VERSION, 'view/version'
6
6
 
7
- mattr_accessor :guessing_methods
8
- self.guessing_methods = %w|to_label display_name full_name name title username login value to_s|
7
+ class << self
8
+ # Used by the guess filter, these are the methods used to format an object.
9
+ # It will use the first method that the object responds to.
10
+ attr_accessor :guessing_methods
9
11
 
10
- mattr_accessor :file_methods
11
- self.file_methods = %w|mounted_as file? public_filename|
12
+ # To determine if something is an uploaded image, it checks
13
+ # to see whether it responds to one of these methods.
14
+ attr_accessor :file_methods
12
15
 
13
- mattr_accessor :path_methods
14
- self.path_methods = %w|mounted_as url public_filename|
16
+ # To show an image, it will use one of these methods to get the src
17
+ # attribute.
18
+ attr_accessor :path_methods
15
19
 
16
- mattr_accessor :path_arguments
17
- self.path_arguments = []
20
+ # You can set a default argument for rendering images, like the style or size
21
+ # of the image. It will be passed to one of the path_methods.
22
+ attr_accessor :path_arguments
18
23
 
19
- mattr_accessor :default_formatter
20
- self.default_formatter = :auto
24
+ # Which formatter will be used by default. The default is auto, which does
25
+ # all sorts of interesting stuff to see what to do.
26
+ attr_accessor :default_formatter
21
27
 
22
- mattr_accessor :formatters
28
+ # The auto formatter will choose this formatter by default when your value is
29
+ # an array (or really, something that responds to +each+).
30
+ attr_accessor :default_list_formatter
23
31
 
32
+ # Holds a list of formatters. It will be filled automatically by inheriting
33
+ # from View::Formatter.
34
+ attr_accessor :formatters
24
35
 
25
- def self.to_s(value, options = {}, template = nil, &block)
26
- Formatter.to_s(value, options, template, &block)
36
+ # Shorthand for configuring this gem.
37
+ #
38
+ # @example In +config/initializers/view.rb+
39
+ #
40
+ # View.configure do |config|
41
+ # config.default_formatter = :self
42
+ # end
43
+ #
44
+ # @yield [config] The View module
45
+ def configure
46
+ yield self
47
+ end
48
+
49
+ end
50
+
51
+ self.guessing_methods = %w|to_label display_name full_name name title
52
+ username login value to_s|
53
+ self.file_methods = %w|mounted_as file? public_filename|
54
+ self.path_methods = %w|mounted_as url public_filename|
55
+ self.path_arguments = []
56
+ self.default_formatter = :auto
57
+ self.default_list_formatter = :sentence
58
+
59
+
60
+ # This is the main method to use this gem. Any formatting from outside this
61
+ # gem should be done through this method (notwithstanding custom formatters).
62
+ #
63
+ # In every day usage you will access it through the +view+ helper method,
64
+ # because most formatters require a view to render links or images. Any
65
+ # helper method should also point to this method.
66
+ #
67
+ # @see View::Helper#view
68
+ #
69
+ # @example Rendering a link
70
+ # module PostsHelper
71
+ # def link_to_post
72
+ # View.format @post, :as => :link, self
73
+ # end
74
+ # end
75
+ #
76
+ # @param [Object] value the object to be shown
77
+ # @param [Hash] options Any extra options
78
+ #
79
+ # @option options [Symbol] :as (:auto) The name of the formatter
80
+ # @option options [Array] :block_arguments (nil) Overrides the arguments passed to
81
+ # the block of this method.
82
+ #
83
+ # @param [ActionView::Template] Template the view instance on which to call
84
+ # helper methods like +link_to+ and +image_tag+.
85
+ # You need this for many formatters.
86
+ #
87
+ # @yield [formatted_string] The block will be captured (using the template if
88
+ # possible) to alter the formatted string that would otherwise be returned.
89
+ # Consider it as a final modifier after the view formatter has done its
90
+ # work.
91
+ #
92
+ # @return [String] the object formatted to a string
93
+ def self.format(value, options = {}, template = nil, &block)
94
+ Formatter.format(value, options, template, &block)
27
95
  end
28
96
 
29
97
  end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe "View::Formatter" do
4
+
5
+ it "doesn't touch strings" do
6
+ View.format("bar").should == "bar"
7
+ end
8
+
9
+ it "parses the block" do
10
+ View.format("bar") { |val| val.upcase }.should == "BAR"
11
+ end
12
+
13
+ end
@@ -2,24 +2,21 @@ require 'spec_helper'
2
2
 
3
3
  describe "Auto formatter" do
4
4
 
5
- it "guesses the to_label" do
6
- object = Struct.new(:to_label).new("some label")
7
- View.to_s(object).should == "some label"
5
+ it "formats like a boolean automatically" do
6
+ View.format(true).should == "Yes"
8
7
  end
9
8
 
10
- it "guesses to_s" do
11
- object = Struct.new(:to_s).new("string")
12
- View.to_s(object).should == "string"
13
- end
14
-
15
- it "guesses a name" do
16
- object = Struct.new(:name).new("my name")
17
- View.to_s(object).should == "my name"
18
- end
19
-
20
- it "guesses a login" do
21
- object = Struct.new(:login).new("loginname")
22
- View.to_s(object).should == "loginname"
9
+ it "is configurable" do
10
+ foo = Class.new(View::Formatter) do
11
+ as :foo
12
+ def format
13
+ "!!!#{value}!!!"
14
+ end
15
+ end
16
+ View::Auto.add :foo do
17
+ value == "foobar"
18
+ end
19
+ View.format("foobar").should == "!!!foobar!!!"
23
20
  end
24
21
 
25
22
  end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Blank formatter" do
4
+
5
+ it "formats nil" do
6
+ View.format(nil).should == ""
7
+ end
8
+
9
+ it "formats empty strings" do
10
+ View.format(" ").should == ""
11
+ end
12
+
13
+ it "formats empty arrays" do
14
+ View.format([]).should == ""
15
+ end
16
+
17
+ it "uses i18n for nil" do
18
+ with_translation :view => { :blank => "nothing" } do
19
+ View.format(nil).should == "nothing"
20
+ end
21
+ end
22
+
23
+ end
@@ -3,24 +3,24 @@ require 'spec_helper'
3
3
  describe "Boolean formatter" do
4
4
 
5
5
  it "formats true" do
6
- View.to_s(true).should == "Yes"
6
+ View.format(true).should == "Yes"
7
7
  end
8
8
 
9
9
  it "formats false" do
10
- View.to_s(false).should == "No"
10
+ View.format(false).should == "No"
11
11
  end
12
12
 
13
13
  it "formats boolean values" do
14
- View.to_s("h", :as => :boolean).should == "Yes"
15
- View.to_s(nil, :as => :boolean).should == "No"
14
+ View.format("h", :as => :boolean).should == "Yes"
15
+ View.format(nil, :as => :boolean).should == "No"
16
16
  end
17
17
 
18
18
  it "localizes booleans" do
19
19
  with_translation :view => { :booleans => { :true => "yup" } } do
20
- View.to_s(true).should == "yup"
20
+ View.format(true).should == "yup"
21
21
  end
22
22
  with_translation :view => { :booleans => { :false => "nope" } } do
23
- View.to_s(false).should == "nope"
23
+ View.format(false).should == "nope"
24
24
  end
25
25
  end
26
26
 
@@ -5,18 +5,18 @@ describe "Date formatter" do
5
5
  it "localizes dates" do
6
6
  date = Date.new(2010, 10, 11)
7
7
  with_translation :date => { :formats => { :foo => "%A" }, :day_names => [ "zondag", "maandag" ] } do
8
- View.to_s(date, :format => :foo).should == "maandag"
8
+ View.format(date, :format => :foo).should == "maandag"
9
9
  end
10
10
  end
11
11
 
12
12
  it "formats dates" do
13
13
  date = Date.new(2010, 10, 10)
14
- View.to_s(date).should == "2010-10-10"
14
+ View.format(date).should == "2010-10-10"
15
15
  end
16
16
 
17
17
  it "forces datetimes to date" do
18
18
  time = Time.new(2010, 10, 10, 8, 45, 30, '+01:00')
19
- View.to_s(time, :as => :date).should == "2010-10-10"
19
+ View.format(time, :as => :date).should == "2010-10-10"
20
20
  end
21
21
 
22
22
  end
@@ -4,13 +4,13 @@ describe "Datetime formatter" do
4
4
 
5
5
  it "formats" do
6
6
  time = Time.new(2010, 10, 10, 8, 45, 30, '+01:00')
7
- View.to_s(time).should == "Sun, 10 Oct 2010 08:45:30 +0100"
7
+ View.format(time).should == "Sun, 10 Oct 2010 08:45:30 +0100"
8
8
  end
9
9
 
10
10
  it "localizes" do
11
11
  time = Time.new(2010, 10, 10, 8, 45, 30, '+01:00')
12
12
  with_translation :time => { :formats => { :short => "%d-%m-%Y %H:%M" } } do
13
- View.to_s(time, :format => :short).should == "10-10-2010 08:45"
13
+ View.format(time, :format => :short).should == "10-10-2010 08:45"
14
14
  end
15
15
  end
16
16
 
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Guess formatter" do
4
+
5
+ it "guesses the to_label" do
6
+ object = Struct.new(:to_label).new("some label")
7
+ View.format(object).should == "some label"
8
+ end
9
+
10
+ it "guesses to_s" do
11
+ object = Struct.new(:to_s).new("string")
12
+ View.format(object).should == "string"
13
+ end
14
+
15
+ it "guesses a name" do
16
+ object = Struct.new(:name).new("my name")
17
+ View.format(object).should == "my name"
18
+ end
19
+
20
+ it "guesses a login" do
21
+ object = Struct.new(:login).new("loginname")
22
+ View.format(object).should == "loginname"
23
+ end
24
+
25
+ end
@@ -4,7 +4,7 @@ describe "Self formatter" do
4
4
 
5
5
  it "doesn't format with formatter self" do
6
6
  time = Time.now
7
- View.to_s(time, :as => :self).should == time
7
+ View.format(time, :as => :self).should == time
8
8
  end
9
9
 
10
10
  end
@@ -4,7 +4,23 @@ describe "Sentence formatter" do
4
4
 
5
5
  it "constructs a sentence" do
6
6
  object = [ 1, 2, 3 ]
7
- View.to_s(object).should == "1, 2, and 3"
7
+ View.format(object).should == "1, 2, and 3"
8
+ end
9
+
10
+ it "has options for each element" do
11
+ object = [ Date.today ]
12
+ subject = View.format(object, :each => { :format => :short })
13
+ subject.should == I18n.l(Date.today, :format => :short)
14
+ end
15
+
16
+ it "makes the sentence html safe if all elements are" do
17
+ object = [ "safe".html_safe ]
18
+ View.format(object).should be_html_safe
19
+ end
20
+
21
+ it "doesn't make the sentence html safe if not all elements are safe" do
22
+ object = [ "safe".html_safe, "unsafe" ]
23
+ View.format(object).should_not be_html_safe
8
24
  end
9
25
 
10
26
  end
metadata CHANGED
@@ -7,8 +7,8 @@ version: !ruby/object:Gem::Version
7
7
  - 0
8
8
  - 0
9
9
  - alpha
10
- - 1
11
- version: 1.0.0.alpha.1
10
+ - 2
11
+ version: 1.0.0.alpha.2
12
12
  platform: ruby
13
13
  authors:
14
14
  - Iain Hecker
@@ -16,10 +16,24 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2010-10-03 00:00:00 +02:00
19
+ date: 2010-10-10 00:00:00 +02:00
20
20
  default_executable:
21
- dependencies: []
22
-
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
23
+ name: rails
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ~>
29
+ - !ruby/object:Gem::Version
30
+ segments:
31
+ - 3
32
+ - 0
33
+ - 0
34
+ version: 3.0.0
35
+ type: :runtime
36
+ version_requirements: *id001
23
37
  description: A very extensible way of viewing objects, easily integrated with other gems
24
38
  email:
25
39
  - iain@iain.nl
@@ -31,18 +45,20 @@ extra_rdoc_files:
31
45
  - README.rdoc
32
46
  files:
33
47
  - lib/view/formatter.rb
48
+ - lib/view/formatters/array.rb
34
49
  - lib/view/formatters/auto.rb
50
+ - lib/view/formatters/blank.rb
35
51
  - lib/view/formatters/boolean.rb
36
52
  - lib/view/formatters/currency.rb
37
53
  - lib/view/formatters/date.rb
38
54
  - lib/view/formatters/datetime.rb
39
55
  - lib/view/formatters/delimited.rb
40
56
  - lib/view/formatters/file_link.rb
57
+ - lib/view/formatters/guess.rb
41
58
  - lib/view/formatters/html_safe.rb
42
59
  - lib/view/formatters/human.rb
43
60
  - lib/view/formatters/image.rb
44
61
  - lib/view/formatters/link.rb
45
- - lib/view/formatters/nil.rb
46
62
  - lib/view/formatters/percentage.rb
47
63
  - lib/view/formatters/phone.rb
48
64
  - lib/view/formatters/precision.rb
@@ -56,15 +72,16 @@ files:
56
72
  - init.rb
57
73
  - README.rdoc
58
74
  - spec/spec_helper.rb
75
+ - spec/view/formatter_spec.rb
59
76
  - spec/view/formatters/auto_spec.rb
77
+ - spec/view/formatters/blank_spec.rb
60
78
  - spec/view/formatters/boolean_spec.rb
61
79
  - spec/view/formatters/date_spec.rb
62
80
  - spec/view/formatters/datetime_spec.rb
63
- - spec/view/formatters/nil_spec.rb
81
+ - spec/view/formatters/guess_spec.rb
64
82
  - spec/view/formatters/self_spec.rb
65
83
  - spec/view/formatters/sentence_spec.rb
66
84
  - spec/view/helper_spec.rb
67
- - spec/view/view_spec.rb
68
85
  has_rdoc: true
69
86
  homepage: http://github.com/iain/view
70
87
  licenses: []
@@ -101,12 +118,13 @@ specification_version: 3
101
118
  summary: Displaying objects automatically
102
119
  test_files:
103
120
  - spec/spec_helper.rb
121
+ - spec/view/formatter_spec.rb
104
122
  - spec/view/formatters/auto_spec.rb
123
+ - spec/view/formatters/blank_spec.rb
105
124
  - spec/view/formatters/boolean_spec.rb
106
125
  - spec/view/formatters/date_spec.rb
107
126
  - spec/view/formatters/datetime_spec.rb
108
- - spec/view/formatters/nil_spec.rb
127
+ - spec/view/formatters/guess_spec.rb
109
128
  - spec/view/formatters/self_spec.rb
110
129
  - spec/view/formatters/sentence_spec.rb
111
130
  - spec/view/helper_spec.rb
112
- - spec/view/view_spec.rb
@@ -1,11 +0,0 @@
1
- module View
2
-
3
- class Nil < Formatter
4
-
5
- def to_s
6
- ::I18n.t(:nil, :scope => :view, :default => "")
7
- end
8
-
9
- end
10
-
11
- end
@@ -1,15 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe "Nil formatter" do
4
-
5
- it "formats nil" do
6
- View.to_s(nil).should == ""
7
- end
8
-
9
- it "uses i18n for nil" do
10
- with_translation :view => { :nil => "nothing" } do
11
- View.to_s(nil).should == "nothing"
12
- end
13
- end
14
-
15
- end
@@ -1,13 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe "View" do
4
-
5
- it "doesn't touch strings" do
6
- View.to_s("bar").should == "bar"
7
- end
8
-
9
- it "parses the block" do
10
- View.to_s("bar") { |val| val.upcase }.should == "BAR"
11
- end
12
-
13
- end