sinatra-support 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/HISTORY.md ADDED
@@ -0,0 +1,53 @@
1
+ v1.0.1 - Mar 27, 2011
2
+ ---------------------
3
+
4
+ ### Added:
5
+ * Implement Sinatra::I18nSupport
6
+
7
+ ### Misc:
8
+ * Update README with URLs
9
+ * Correct the wrong gem name in the documentation
10
+
11
+ v1.0.0 - Mar 27, 2011
12
+ ---------------------
13
+
14
+ Massive 1.0 refactor and massive documentation update. Now sporting a
15
+ completely new API and breaks compatibility with 0.2.0.
16
+
17
+ ### Added:
18
+ * CssSupport
19
+ * JsSupport
20
+ * IfHelpers
21
+
22
+ v0.2.0
23
+ ------
24
+
25
+ ### Fixed:
26
+ * documentation for private objects / methods
27
+
28
+ ### Added:
29
+ * currency helpers with tests and documentation
30
+ * day_choices
31
+ * full docs to all helper methods
32
+ * link to docs
33
+
34
+ ### Removed:
35
+ * old sinatra-helpers files
36
+
37
+ ### Changed:
38
+ * Allow descending year_choices
39
+ * change how tag works for self_closing
40
+ * Initial renamed sprint from sinatra-helpers
41
+ * Tweak documentation for Methods.rb and load order
42
+ * select option tweaks
43
+
44
+ v0.1.1
45
+ ------
46
+
47
+ ### Changed:
48
+ * some tweaks for ruby1.8.6 compat
49
+
50
+ v0.1.0
51
+ ------
52
+
53
+ Initial version.
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ task(:test) {
2
+ Dir['./test/**/test_*.rb'].each { |f| load f }
3
+ }
4
+
5
+ task(:update_doc) {
6
+ system "yard && cd doc && git add . && git add -u && git commit -m . && git push"
7
+ }
@@ -0,0 +1,30 @@
1
+ # Taken from ohm
2
+
3
+ unless "".respond_to?(:lines)
4
+ # @private 1.8.6 compatibility only
5
+ class String
6
+ # @private
7
+ # This version of String#lines is almost fully compatible with that
8
+ # of Ruby 1.9. If a zero-length record separator is supplied in Ruby
9
+ # 1.9, the string is split into paragraphs delimited by multiple
10
+ # successive newlines. This replacement ignores that feature in
11
+ # favor of code simplicity.
12
+ def lines(separator = $/)
13
+ result = split(separator).map { |part| "#{part}#{separator}" }
14
+ result.each { |r| yield r } if block_given?
15
+ result
16
+ end
17
+ end
18
+ end
19
+
20
+ unless respond_to?(:tap)
21
+ # @private 1.8.6 compatibility only
22
+ class Object
23
+ # @private no need to explain. Standard ruby 1.9 stuff.
24
+ # @see http://ruby-doc.org/ruby-1.9/classes/Object.html#M000239
25
+ def tap
26
+ yield(self)
27
+ self
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,300 @@
1
+ # encoding: UTF-8
2
+
3
+ # A simple module containing all countries as of 2010.
4
+ #
5
+ module Sinatra::Country
6
+ @all = {
7
+ :AF => "Afghanistan",
8
+ :AX => "Åland Islands",
9
+ :AL => "Albania",
10
+ :DZ => "Algeria",
11
+ :AS => "American Samoa",
12
+ :AD => "Andorra",
13
+ :AO => "Angola",
14
+ :AI => "Anguilla",
15
+ :AQ => "Antarctica",
16
+ :AG => "Antigua and Barbuda",
17
+ :AR => "Argentina",
18
+ :AM => "Armenia",
19
+ :AW => "Aruba",
20
+ :AU => "Australia",
21
+ :AT => "Austria",
22
+ :AZ => "Azerbaijan",
23
+ :BS => "Bahamas",
24
+ :BH => "Bahrain",
25
+ :BD => "Bangladesh",
26
+ :BB => "Barbados",
27
+ :BY => "Belarus",
28
+ :BE => "Belgium",
29
+ :BZ => "Belize",
30
+ :BJ => "Benin",
31
+ :BM => "Bermuda",
32
+ :BT => "Bhutan",
33
+ :BO => "Bolivia, Plurinational State of",
34
+ :BA => "Bosnia and Herzegovina",
35
+ :BW => "Botswana",
36
+ :BV => "Bouvet Island",
37
+ :BR => "Brazil",
38
+ :IO => "British Indian Ocean Territory",
39
+ :BN => "Brunei Darussalam",
40
+ :BG => "Bulgaria",
41
+ :BF => "Burkina Faso",
42
+ :BI => "Burundi",
43
+ :KH => "Cambodia",
44
+ :CM => "Cameroon",
45
+ :CA => "Canada",
46
+ :CV => "Cape Verde",
47
+ :KY => "Cayman Islands",
48
+ :CF => "Central African Republic",
49
+ :TD => "Chad",
50
+ :CL => "Chile",
51
+ :CN => "China",
52
+ :CX => "Christmas Island",
53
+ :CC => "Cocos (Keeling) Islands",
54
+ :CO => "Colombia",
55
+ :KM => "Comoros",
56
+ :CG => "Congo",
57
+ :CD => "Congo, the Democratic Republic of the",
58
+ :CK => "Cook Islands",
59
+ :CR => "Costa Rica",
60
+ :CI => "CÔte D'ivoire",
61
+ :HR => "Croatia",
62
+ :CU => "Cuba",
63
+ :CY => "Cyprus",
64
+ :CZ => "Czech Republic",
65
+ :DK => "Denmark",
66
+ :DJ => "Djibouti",
67
+ :DM => "Dominica",
68
+ :DO => "Dominican Republic",
69
+ :EC => "Ecuador",
70
+ :EG => "Egypt",
71
+ :SV => "El Salvador",
72
+ :GQ => "Equatorial Guinea",
73
+ :ER => "Eritrea",
74
+ :EE => "Estonia",
75
+ :ET => "Ethiopia",
76
+ :FK => "Falkland Islands (Malvinas)",
77
+ :FO => "Faroe Islands",
78
+ :FJ => "Fiji",
79
+ :FI => "Finland",
80
+ :FR => "France",
81
+ :GF => "French Guiana",
82
+ :PF => "French Polynesia",
83
+ :TF => "French Southern Territories",
84
+ :GA => "Gabon",
85
+ :GM => "Gambia",
86
+ :GE => "Georgia",
87
+ :DE => "Germany",
88
+ :GH => "Ghana",
89
+ :GI => "Gibraltar",
90
+ :GR => "Greece",
91
+ :GL => "Greenland",
92
+ :GD => "Grenada",
93
+ :GP => "Guadeloupe",
94
+ :GU => "Guam",
95
+ :GT => "Guatemala",
96
+ :GG => "Guernsey",
97
+ :GN => "Guinea",
98
+ :GW => "Guinea-bissau",
99
+ :GY => "Guyana",
100
+ :HT => "Haiti",
101
+ :HM => "Heard Island and Mcdonald Islands",
102
+ :VA => "Holy See (Vatican City State)",
103
+ :HN => "Honduras",
104
+ :HK => "Hong Kong",
105
+ :HU => "Hungary",
106
+ :IS => "Iceland",
107
+ :IN => "India",
108
+ :ID => "Indonesia",
109
+ :IR => "Iran, Islamic Republic of",
110
+ :IQ => "Iraq",
111
+ :IE => "Ireland",
112
+ :IM => "Isle of Man",
113
+ :IL => "Israel",
114
+ :IT => "Italy",
115
+ :JM => "Jamaica",
116
+ :JP => "Japan",
117
+ :JE => "Jersey",
118
+ :JO => "Jordan",
119
+ :KZ => "Kazakhstan",
120
+ :KE => "Kenya",
121
+ :KI => "Kiribati",
122
+ :KP => "Korea, Democratic People's Republic of",
123
+ :KR => "Korea, Republic of",
124
+ :KW => "Kuwait",
125
+ :KG => "Kyrgyzstan",
126
+ :LA => "Lao People's Democratic Republic",
127
+ :LV => "Latvia",
128
+ :LB => "Lebanon",
129
+ :LS => "Lesotho",
130
+ :LR => "Liberia",
131
+ :LY => "Libyan Arab Jamahiriya",
132
+ :LI => "Liechtenstein",
133
+ :LT => "Lithuania",
134
+ :LU => "Luxembourg",
135
+ :MO => "Macao",
136
+ :MK => "Macedonia, the Former Yugoslav Republic of",
137
+ :MG => "Madagascar",
138
+ :MW => "Malawi",
139
+ :MY => "Malaysia",
140
+ :MV => "Maldives",
141
+ :ML => "Mali",
142
+ :MT => "Malta",
143
+ :MH => "Marshall Islands",
144
+ :MQ => "Martinique",
145
+ :MR => "Mauritania",
146
+ :MU => "Mauritius",
147
+ :YT => "Mayotte",
148
+ :MX => "Mexico",
149
+ :FM => "Micronesia, Federated States of",
150
+ :MD => "Moldova, Republic of",
151
+ :MC => "Monaco",
152
+ :MN => "Mongolia",
153
+ :ME => "Montenegro",
154
+ :MS => "Montserrat",
155
+ :MA => "Morocco",
156
+ :MZ => "Mozambique",
157
+ :MM => "Myanmar",
158
+ :NA => "Namibia",
159
+ :NR => "Nauru",
160
+ :NP => "Nepal",
161
+ :NL => "Netherlands",
162
+ :AN => "Netherlands Antilles",
163
+ :NC => "New Caledonia",
164
+ :NZ => "New Zealand",
165
+ :NI => "Nicaragua",
166
+ :NE => "Niger",
167
+ :NG => "Nigeria",
168
+ :NU => "Niue",
169
+ :NF => "Norfolk Island",
170
+ :MP => "Northern Mariana Islands",
171
+ :NO => "Norway",
172
+ :OM => "Oman",
173
+ :PK => "Pakistan",
174
+ :PW => "Palau",
175
+ :PS => "Palestinian Territory, Occupied",
176
+ :PA => "Panama",
177
+ :PG => "Papua New Guinea",
178
+ :PY => "Paraguay",
179
+ :PE => "Peru",
180
+ :PH => "Philippines",
181
+ :PN => "Pitcairn",
182
+ :PL => "Poland",
183
+ :PT => "Portugal",
184
+ :PR => "Puerto Rico",
185
+ :QA => "Qatar",
186
+ :RE => "RÉunion",
187
+ :RO => "Romania",
188
+ :RU => "Russian Federation",
189
+ :RW => "Rwanda",
190
+ :BL => "Saint BarthÉlemy",
191
+ :SH => "Saint Helena, Ascension and Tristan Da Cunha",
192
+ :KN => "Saint Kitts and Nevis",
193
+ :LC => "Saint Lucia",
194
+ :MF => "Saint Martin",
195
+ :PM => "Saint Pierre and Miquelon",
196
+ :VC => "Saint Vincent and the Grenadines",
197
+ :WS => "Samoa",
198
+ :SM => "San Marino",
199
+ :ST => "Sao Tome and Principe",
200
+ :SA => "Saudi Arabia",
201
+ :SN => "Senegal",
202
+ :RS => "Serbia",
203
+ :SC => "Seychelles",
204
+ :SL => "Sierra Leone",
205
+ :SG => "Singapore",
206
+ :SK => "Slovakia",
207
+ :SI => "Slovenia",
208
+ :SB => "Solomon Islands",
209
+ :SO => "Somalia",
210
+ :ZA => "South Africa",
211
+ :GS => "South Georgia and the South Sandwich Islands",
212
+ :ES => "Spain",
213
+ :LK => "Sri Lanka",
214
+ :SD => "Sudan",
215
+ :SR => "Suriname",
216
+ :SJ => "Svalbard and Jan Mayen",
217
+ :SZ => "Swaziland",
218
+ :SE => "Sweden",
219
+ :CH => "Switzerland",
220
+ :SY => "Syrian Arab Republic",
221
+ :TW => "Taiwan, Province of China",
222
+ :TJ => "Tajikistan",
223
+ :TZ => "Tanzania, United Republic of",
224
+ :TH => "Thailand",
225
+ :TL => "Timor-leste",
226
+ :TG => "Togo",
227
+ :TK => "Tokelau",
228
+ :TO => "Tonga",
229
+ :TT => "Trinidad and Tobago",
230
+ :TN => "Tunisia",
231
+ :TR => "Turkey",
232
+ :TM => "Turkmenistan",
233
+ :TC => "Turks and Caicos Islands",
234
+ :TV => "Tuvalu",
235
+ :UG => "Uganda",
236
+ :UA => "Ukraine",
237
+ :AE => "United Arab Emirates",
238
+ :GB => "United Kingdom",
239
+ :US => "United States",
240
+ :UM => "United States Minor Outlying Islands",
241
+ :UY => "Uruguay",
242
+ :UZ => "Uzbekistan",
243
+ :VU => "Vanuatu",
244
+ :VA => "Vatican City State",
245
+ :VE => "Venezuela, Bolivarian Republic of",
246
+ :VN => "Viet Nam",
247
+ :VG => "Virgin Islands, British",
248
+ :VI => "Virgin Islands, U.S.",
249
+ :WF => "Wallis and Futuna",
250
+ :EH => "Western Sahara",
251
+ :YE => "Yemen",
252
+ :ZM => "Zambia",
253
+ :ZW => "Zimbabwe"
254
+ }
255
+
256
+ # @example
257
+ #
258
+ # p Country.to_select
259
+ # [["Afghanistan", "AF"], ["Åland Islands", "AX"], ["Albania", "AL"],
260
+ # ["Algeria", "DZ"], ["American Samoa", "AS"], ... ["Zimbabwe", "ZW"]]
261
+ #
262
+ # @return [Array] a collection of pairs with the first element being
263
+ # country name and the last element being the code.
264
+ #
265
+ # @see Sinatra#country_choices
266
+ def to_select
267
+ all.map { |code, name| [name, code.to_s] }
268
+ end
269
+
270
+ # Retrieves the country name given a country code.
271
+ # @example
272
+ #
273
+ # Sinatra::Country["US"] == "United States"
274
+ # # => true
275
+ #
276
+ # Sinatra::Country[:US] == "United States"
277
+ # # => true
278
+ #
279
+ # @param [#to_sym] code The country code in 2 letter all caps format.
280
+ # @return [String] The corresponding country name given the code.
281
+ # @return [nil] nil if no matching country code.
282
+ def [](code)
283
+ all[code.to_sym] if not code.to_s.empty?
284
+ end
285
+
286
+ # For use with seeding dummy data.
287
+ # @return [Symbol] a randomized country code.
288
+ def random
289
+ all.keys.shuffle.first
290
+ end
291
+
292
+ # Gives all countries in a Hash.
293
+ #
294
+ # @return [Hash] the code => name pairs of all countries.
295
+ def all
296
+ @all
297
+ end
298
+
299
+ module_function :all, :to_select, :[], :random
300
+ end
@@ -0,0 +1,28 @@
1
+ require File.expand_path('../country', __FILE__)
2
+
3
+ # Country helpers.
4
+ #
5
+ # require 'sinatra/support/countryhelpers'
6
+ # require 'sinatra/support/htmlhelpers'
7
+ #
8
+ # class Main < Sinatra::Base
9
+ # helpers Sinatra::HtmlHelpers
10
+ # helpers Sinatra::CountryHelpers
11
+ # end
12
+ #
13
+ # == Helpers
14
+ #
15
+ # Provides the following helpers:
16
+ #
17
+ # === {#country_choices country_choices} - Country choices for select_options.
18
+ #
19
+ # <!-- A dropdown box of countries. -->
20
+ # <select name="country">
21
+ # <%= select_options country_choices %>
22
+ # </select>
23
+ #
24
+ module Sinatra::CountryHelpers
25
+ def country_choices
26
+ Sinatra::Country.to_select
27
+ end
28
+ end
@@ -0,0 +1,58 @@
1
+ # Support for Sass/SCSS/Less.
2
+ #
3
+ # == Usage
4
+ #
5
+ # require 'sinatra/support/csssupport'
6
+ #
7
+ # Use {#serve_css} in the Sinatra DSL to serve up files.
8
+ #
9
+ # register Sinatra::CssSupport
10
+ # serve_css '/styles', from: './app/css'
11
+ #
12
+ # Assuming you have a +app/css/print.scss+ file, you will
13
+ # then be able to access it from the given URL prefix.
14
+ #
15
+ # $ curl "http://localhost:4567/styles/print.css"
16
+ #
17
+ # This plugin supports Sass, Less and SCSS and guesses by the
18
+ # file name.
19
+ #
20
+ # == Caveats
21
+ #
22
+ # Note that you will need to set your Sass/SCSS +load_path+ settings.
23
+ #
24
+ # Main.configure do |m|
25
+ # m.set :scss, {
26
+ # :load_paths => [ 'app/css' ]
27
+ # }
28
+ # m.set :scss, self.scss.merge(:style => :compressed) if m.production?
29
+ # end
30
+ #
31
+ module Sinatra::CssSupport
32
+ def self.registered(app)
33
+ app.set :css_max_age, app.development? ? 0 : 86400*30
34
+ end
35
+
36
+ def serve_css(url_prefix, options={})
37
+ path = File.join(url_prefix, '*.css')
38
+ prefix = options[:from]
39
+
40
+ get path do |name|
41
+ fname = Dir[File.join(prefix, "#{name}.{css,scss,less}")].first or pass
42
+
43
+ content_type :css, :charset => 'utf-8'
44
+ last_modified File.mtime(fname)
45
+ cache_control :public, :must_revalidate, :max_age => settings.css_max_age
46
+
47
+ if fname =~ /\.scss$/
48
+ scss File.read(fname)
49
+ elsif fname =~ /\.scss$/
50
+ sass File.read(fname)
51
+ elsif fname =~ /\.less$/
52
+ less File.read(fname)
53
+ else
54
+ send_file fname
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,145 @@
1
+ require File.expand_path('../compat-1.8.6.rb', __FILE__)
2
+
3
+ # Date helpers.
4
+ #
5
+ # require 'sinatra/support/dateforms'
6
+ #
7
+ # class Main < Sinatra::Base
8
+ # register Sinatra::DateForms
9
+ # end
10
+ #
11
+ # == Helpers
12
+ #
13
+ # This plugin provides the following helpers:
14
+ #
15
+ # === {Helpers#month_choices month_choices} - Provides month choices for dropdowns.
16
+ #
17
+ # <select name="birthday[month]">
18
+ # <%= month_choices %>
19
+ # </select>
20
+ #
21
+ # === {Helpers#day_choices day_choices} - Day choices.
22
+ #
23
+ # <select name="birthday[day]">
24
+ # <%= day_choices %>
25
+ # </select>
26
+ #
27
+ # === {Helpers#year_choices year_choices} - Year dropdown.
28
+ #
29
+ # <select name="birthday[year]">
30
+ # <%= year_choices %>
31
+ # </select>
32
+ #
33
+ # == Settings
34
+ #
35
+ # Provides the following settings in your application:
36
+ #
37
+ # [+default_year_loffset+] (Numeric) How many years back to display.
38
+ # Defaults to +-60+.
39
+ # [+default_year_loffset+] (Numeric) How many years forward. Defaults
40
+ # to +0+.
41
+ # [+default_month_names+] (Array) The names of the months. Defaults
42
+ # To +Date::MONTHNAMES+.
43
+ #
44
+ # You may change them like this:
45
+ #
46
+ # Main.configure do |m|
47
+ # m.set :default_year_loffset, -60
48
+ # m.set :default_year_uoffset, 0
49
+ # m.set :default_month_names, Date::MONTHNAMES
50
+ # end
51
+ #
52
+ module Sinatra::DateForms
53
+ def self.registered(app)
54
+ app.set :default_year_loffset, -60
55
+ app.set :default_year_uoffset, 0
56
+ app.set :default_month_names, Date::MONTHNAMES
57
+
58
+ app.helpers Helpers
59
+ end
60
+
61
+ module Helpers
62
+ # Returns an array of date pairs. Best used with
63
+ # {Sinatra::HtmlHelpers#select_options}.
64
+ #
65
+ # @return [Array] the array of day, day pairs.
66
+ #
67
+ # @example This is perfect for @select_options@.
68
+ #
69
+ # <select name="date">
70
+ # <%= select_options day_choices %>
71
+ #
72
+ # An example output looks like:
73
+ #
74
+ # - [1, 1]
75
+ # - [2, 2]
76
+ # - ...
77
+ # - [31, 31]
78
+ #
79
+ def day_choices(max=31)
80
+ days = (1..max).to_a
81
+ days.zip(days)
82
+ end
83
+
84
+ # Returns an array of pairs.
85
+ #
86
+ # You may pass in @Date::ABBR_MONTHNAMES@ if you want the shortened month
87
+ # names.
88
+ #
89
+ # @example output
90
+ #
91
+ # - ['January', 1]
92
+ # - ['February', 2]
93
+ # - ...
94
+ # - ['December', 12]
95
+ #
96
+ # @param [Array] month_names (defaults to Date::MONTHNAMES) an array with the
97
+ # first element being nil, element 1 being January, etc.
98
+ # @return [Array] the array of month name, month pairs.
99
+ def month_choices(month_names = settings.default_month_names)
100
+ month_names.map.
101
+ with_index { |month, idx| [month, idx] }.
102
+ tap { |arr| arr.shift }
103
+ end
104
+
105
+ # Returns an array of pairs.
106
+ #
107
+ # @example Output
108
+ #
109
+ # - [2005, 2005]
110
+ # - [2006, 2006]
111
+ # - ...
112
+ # - [2010, 2010]
113
+ #
114
+ # @example
115
+ #
116
+ # year_choices # assuming it's now 2010
117
+ # # => [[1950, 1950], ..., [2010, 2010]]
118
+ #
119
+ # # we can pass in options
120
+ # year_choices(0, 6) # like for credit card options
121
+ # # => [[2010, 2010], ..., [2016, 2016]]
122
+ #
123
+ # # also we can override settings at the app level
124
+ # set :default_year_loffset, 0
125
+ # set :default_year_uoffset, 6
126
+ # year_choices
127
+ # # => [[2010, 2010], ..., [2016, 2016]]
128
+ #
129
+ # @param [Fixnum] loffset (defaults to -60) The lower offset relative to the current year.
130
+ # If it's 2010 now, passing in -5 here will start the year
131
+ # list at 2005 for example.
132
+ # @param [Fixnum] uoffset (defaults to 0) The upper offset relative to the
133
+ # current year. If it's 2010 now, passing in 5 or +5 here
134
+ # will end the year list at 2015 for example.
135
+ # @return [Array] the array of year, year pairs.
136
+ #
137
+ def year_choices(loffset = settings.default_year_loffset, uoffset = settings.default_year_uoffset)
138
+ start = loffset + Date.today.year
139
+ finish = uoffset + Date.today.year
140
+
141
+ enum = start < finish ? start.upto(finish) : start.downto(finish)
142
+ enum.map { |e| [e, e] }
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,62 @@
1
+ # Ohm error helpers.
2
+ #
3
+ # == Usage
4
+ #
5
+ # # Only for those who use Ohm and HAML
6
+ # require 'ohm'
7
+ # require 'haml'
8
+ #
9
+ # require 'sinatra/support/ohmerrorhelpers'
10
+ #
11
+ # class Main < Sinatra::Base
12
+ # helpers Sinatra::OhmErrorHelpers
13
+ # end
14
+ #
15
+ # == Common usage
16
+ #
17
+ # - errors_on @user do |e|
18
+ # - e.on [:email, :not_present], "We need your email address."
19
+ # - e.on [:password, :not_present], "You must specify a password."
20
+ #
21
+ # # produces the following:
22
+ # # <div class="errors">
23
+ # # <ul>
24
+ # # <li>We need your email address</li>
25
+ # # <li>You must specify a password.</li>
26
+ # # </ul>
27
+ # # </div>
28
+ #
29
+ module Sinatra::OhmErrorHelpers
30
+ # Presents errors on your form. Takes the explicit approach and assumes
31
+ # that for every form you have, the copy for the errors are important,
32
+ # instead of producing canned responses.
33
+ #
34
+ # @param [#errors] object An object responding to #errors. This validation
35
+ # also checks for the presence of a #full_messages method
36
+ # in the errors object for compatibility with
37
+ # ActiveRecord style objects.
38
+ # @param [Hash] options a hash of HTML attributes to place on the
39
+ # containing div.
40
+ # @option options [#to_s] :class (defaults to errors) The css class to put
41
+ # in the div.
42
+ #
43
+ # @yield [Sinatra::Support::HamlErrorPresenter] an object responding to #on.
44
+ #
45
+ def errors_on(object, options = { :class => 'errors' }, &block)
46
+ return if object.errors.empty?
47
+
48
+ lines = if object.errors.respond_to?(:full_messages)
49
+ object.errors.full_messages
50
+ else
51
+ HamlErrorPresenter.new(object.errors).present(self, &block)
52
+ end
53
+
54
+ haml_tag(:div, options) do
55
+ haml_tag(:ul) do
56
+ lines.each do |error|
57
+ haml_tag(:li, error)
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end