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

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