any_view 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/.document +5 -0
  2. data/.gitignore +21 -0
  3. data/LICENSE +47 -0
  4. data/README.rdoc +369 -0
  5. data/Rakefile +57 -0
  6. data/lib/any_view/asset_tag_helpers.rb +103 -0
  7. data/lib/any_view/core_ext/array.rb +7 -0
  8. data/lib/any_view/core_ext/hash.rb +41 -0
  9. data/lib/any_view/core_ext/string.rb +17 -0
  10. data/lib/any_view/form_builder/abstract_form_builder.rb +128 -0
  11. data/lib/any_view/form_builder/standard_form_builder.rb +37 -0
  12. data/lib/any_view/form_helpers.rb +217 -0
  13. data/lib/any_view/format_helpers.rb +49 -0
  14. data/lib/any_view/tag_helpers.rb +47 -0
  15. data/lib/any_view/tilt_base.rb +94 -0
  16. data/lib/any_view.rb +30 -0
  17. data/test/fixtures/basic_form_for.erb +3 -0
  18. data/test/fixtures/builder_type_form_for.erb +3 -0
  19. data/test/fixtures/capture_concat.erb +14 -0
  20. data/test/fixtures/capture_concat.haml +13 -0
  21. data/test/fixtures/content_for.erb +11 -0
  22. data/test/fixtures/content_for.haml +9 -0
  23. data/test/fixtures/content_tag.erb +11 -0
  24. data/test/fixtures/content_tag.haml +9 -0
  25. data/test/fixtures/delete_form_for.erb +3 -0
  26. data/test/fixtures/field_set_tag.erb +3 -0
  27. data/test/fixtures/fields_for.erb +8 -0
  28. data/test/fixtures/fields_for.haml +6 -0
  29. data/test/fixtures/fields_for_basic.erb +3 -0
  30. data/test/fixtures/fields_for_nil.erb +3 -0
  31. data/test/fixtures/form_for.erb +56 -0
  32. data/test/fixtures/form_for.haml +47 -0
  33. data/test/fixtures/form_for_nil.erb +3 -0
  34. data/test/fixtures/form_tag.erb +57 -0
  35. data/test/fixtures/form_tag.haml +45 -0
  36. data/test/fixtures/form_tag_methods.erb +19 -0
  37. data/test/fixtures/form_tag_methods.haml +15 -0
  38. data/test/fixtures/link_to.erb +5 -0
  39. data/test/fixtures/link_to.haml +4 -0
  40. data/test/fixtures/mail_to.erb +3 -0
  41. data/test/fixtures/mail_to.haml +3 -0
  42. data/test/fixtures/multipart.erb +12 -0
  43. data/test/fixtures/multipart_form_for.erb +3 -0
  44. data/test/fixtures/put_form_for.erb +3 -0
  45. data/test/fixtures/standard_form_builder.erb +3 -0
  46. data/test/helper.rb +121 -0
  47. data/test/test_asset_tag_helpers.rb +176 -0
  48. data/test/test_form_builder.rb +607 -0
  49. data/test/test_form_helpers.rb +453 -0
  50. data/test/test_format_helpers.rb +59 -0
  51. data/test/test_tag_helpers.rb +65 -0
  52. metadata +160 -0
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/LICENSE ADDED
@@ -0,0 +1,47 @@
1
+ Copyright (c) 2009 Daniel Neighman
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ This software is hevily based on the Pardino framework helpers and as such is bound by it's licence agreement reproduced below.
23
+
24
+ ------------------------------------------------------------------------
25
+
26
+ Copyright (c) 2009 Padrino
27
+
28
+ Permission is hereby granted, free of charge, to any person obtaining
29
+ a copy of this software and associated documentation files (the
30
+ "Software"), to deal in the Software without restriction, including
31
+ without limitation the rights to use, copy, modify, merge, publish,
32
+ distribute, sublicense, and/or sell copies of the Software, and to
33
+ permit persons to whom the Software is furnished to do so, subject to
34
+ the following conditions:
35
+
36
+ The above copyright notice and this permission notice shall be
37
+ included in all copies or substantial portions of the Software.
38
+
39
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
40
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
41
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
42
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
43
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
44
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
45
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
46
+
47
+
data/README.rdoc ADDED
@@ -0,0 +1,369 @@
1
+ = AnyView
2
+
3
+ The AnyView gem provides helpers for common web related view rendering. The AnyView gem is a collection of mixins that work together to provide tags, forms asset paths and more. AnyView is based heavily on the Padrino framework helpers module.
4
+
5
+ The requirements of AnyView are kept very small. There's two required methods inside your view context.
6
+
7
+ capture_content(*args, &block)
8
+
9
+ and
10
+
11
+ concat_content(string, opts ={})
12
+
13
+ By implementing these two methods on your view context, you're able to get just about all the view helpers in anyview including form_for helpers.
14
+
15
+ == Installation
16
+
17
+ $ sudo gem install any_view
18
+
19
+ This will install the required gems. Next, simply include the AnyView module into your view context
20
+
21
+ class ViewContext
22
+ include AnyView
23
+ end
24
+
25
+ If you're using Tilt, then AnyView can provide the capture_content and concat_content helpers too. These will work for erubis, erb and haml templates.
26
+
27
+ class ViewContext
28
+ include AnyView::TiltBase
29
+ include AnyView
30
+ end
31
+
32
+ A full setup for a custom class, including rendering the tilt templates might look like this:
33
+
34
+ class Renderer
35
+ def self.path
36
+ @path ||= File.expand_path(~'./views')
37
+ end
38
+
39
+ def self.template(name)
40
+ @templates ||= {}
41
+ @templates[name] ||= Tilt.new(File.join(path, name))
42
+ @templates[name]
43
+ end
44
+
45
+ def template(name)
46
+ self.class.template(name)
47
+ end
48
+
49
+ def render(name, locals = {})
50
+ template(name).render(ViewContext.new, locals)
51
+ end
52
+ end
53
+
54
+
55
+ Usage would be as simple as
56
+ Renderer.new.render("my_template.erb")
57
+
58
+ == Usage
59
+
60
+ === Tag Helpers
61
+
62
+ Tag helpers are the basic building blocks used to construct html 'tags' within a view template. There
63
+ are three major functions for this category: <tt>tag</tt>, <tt>content_tag</tt> and <tt>input_tag</tt>.
64
+
65
+ The tag and content_tag are for building arbitrary html tags with a name and specified options. If
66
+ the tag contains 'content' within then <tt>content_tag</tt> is used. For example:
67
+
68
+ tag(:br, :style => ‘clear:both’) => <br style="clear:both" />
69
+ content_tag(:p, "demo", :class => ‘light’) => <p class="light">demo</p>
70
+
71
+ The input_tag is used to build tags that are related to accepting input from the user:
72
+
73
+ input_tag :text, :class => "demo" => <input type='text' class='demo' />
74
+ input_tag :password, :value => "secret", :class => "demo"
75
+
76
+ Note that all of these accept html options and result in returning a string containing html tags.
77
+
78
+ The list of defined helpers in the 'tag helpers' category:
79
+
80
+ * <tt>tag(name, options={})</tt>
81
+ * Creates an html tag with the given name and options
82
+ * <tt>tag(:br, :style => 'clear:both')</tt> => <br style="clear:both" />
83
+ * <tt>tag(:p, :content => "demo", :class => 'large')</tt> => <p class="large">demo</p>
84
+ * <tt>content_tag(name, content, options={})</tt>
85
+ * Creates an html tag with given name, content and options
86
+ * <tt>content_tag(:p, "demo", :class => 'light')</tt> => <p class="light">demo</p>
87
+ * <tt>content_tag(:p, :class => 'dark') { ...content... }</tt> => <p class="dark">...content...</p>
88
+ * <tt>input_tag(type, options = {})</tt>
89
+ * Creates an html input field with given type and options
90
+ * <tt>input_tag :text, :class => "demo"</tt>
91
+ * <tt>input_tag :password, :value => "secret", :class => "demo"</tt>
92
+
93
+ === Asset Helpers
94
+
95
+ Asset helpers are intended to help insert useful html onto a view template such as stylesheet link tags ,
96
+ hyperlinks, mail_to links, images, stylesheets and javascript. An example of their uses would be on a
97
+ simple view template:
98
+
99
+ # app/views/example.haml
100
+ ...
101
+ %head
102
+ = stylesheet_link_tag 'layout'
103
+ = javascript_include_tag 'application'
104
+ %body
105
+ ...
106
+ %p= link_to 'Blog', '/blog', :class => 'example'
107
+ %p Mail me at #{mail_to 'fake@faker.com', "Fake Email Link", :cc => "test@demo.com"}
108
+ %p= image_tag 'padrino.png', :width => '35', :class => 'logo'
109
+
110
+ The list of defined helpers in the 'asset helpers' category:
111
+
112
+ * <tt>link_to(*args, &block)</tt>
113
+ * Creates a link element with given name, url and options
114
+ * <tt>link_to 'click me', '/dashboard', :class => 'linky'</tt>
115
+ * <tt>link_to('/dashboard', :class => 'blocky') { ...content... }</tt>
116
+ * <tt>mail_to(email, caption=nil, mail_options={})</tt>
117
+ * Creates a mailto link tag to the specified email_address
118
+ * <tt>mail_to "me@demo.com"</tt>
119
+ * <tt>mail_to "me@demo.com", "My Email", :subject => "Feedback", :cc => 'test@demo.com'</tt>
120
+ * <tt>image_tag(url, options={})</tt>
121
+ * Creates an image element with given url and options
122
+ * <tt>image_tag('icons/avatar.png')</tt>
123
+ * <tt>stylesheet_link_tag(*sources)</tt>
124
+ * Returns a stylesheet link tag for the sources specified as arguments
125
+ * <tt>stylesheet_link_tag 'style', 'application', 'layout'</tt>
126
+ * <tt>javascript_include_tag(*sources)</tt>
127
+ * Returns an html script tag for each of the sources provided.
128
+ * <tt>javascript_include_tag 'application', 'special'</tt>
129
+
130
+ To make use of these in a situation where you're application is in a mounted url space, you should include a method +uri_root+ in your view_context. This allows you to put a uri prifix on the "/stylesheets/my_style.css" relative url
131
+
132
+ === Form Helpers
133
+
134
+ Form helpers are the 'standard' form tag helpers you would come to expect when building forms. A simple
135
+ example of constructing a non-object form would be:
136
+
137
+ - form_tag '/destroy', :class => 'destroy-form', :method => :delete do
138
+ - field_set_tag do
139
+ %p
140
+ = label_tag :username, :class => 'first'
141
+ = text_field_tag :username, :value => params[:username]
142
+ %p
143
+ = label_tag :password, :class => 'first'
144
+ = password_field_tag :password, :value => params[:password]
145
+ %p
146
+ = label_tag :strategy
147
+ = select_tag :strategy, :options => ['delete', 'destroy'], :selected => 'delete'
148
+ %p
149
+ = check_box_tag :confirm_delete
150
+ - field_set_tag(:class => 'buttons') do
151
+ = submit_tag "Remove"
152
+
153
+ The list of defined helpers in the 'form helpers' category:
154
+
155
+ * <tt>form_tag(url, options={}, &block)</tt>
156
+ * Constructs a form without object based on options
157
+ * Supports form methods 'put' and 'delete' through hidden field
158
+ * <tt>form_tag('/register', :class => 'example') { ... }</tt>
159
+ * <tt>field_set_tag(*args, &block)</tt>
160
+ * Constructs a field_set to group fields with given options
161
+ * <tt>field_set_tag(:class => 'office-set') { }</tt>
162
+ * <tt>field_set_tag("Office", :class => 'office-set') { }</tt>
163
+ * <tt>error_messages_for(record, options={})</tt>
164
+ * Constructs list html for the errors for a given object
165
+ * <tt>error_messages_for @user</tt>
166
+ * <tt>label_tag(name, options={}, &block)</tt>
167
+ * Constructs a label tag from the given options
168
+ * <tt>label_tag :username, :class => 'long-label'</tt>
169
+ * <tt>label_tag(:username, :class => 'blocked-label') { ... }</tt>
170
+ * <tt>hidden_field_tag(name, options={})</tt>
171
+ * Constructs a hidden field input from the given options
172
+ * <tt>hidden_field_tag :session_key, :value => 'secret'</tt>
173
+ * <tt>text_field_tag(name, options={})</tt>
174
+ * Constructs a text field input from the given options
175
+ * <tt>text_field_tag :username, :class => 'long'</tt>
176
+ * <tt>text_area_tag(name, options={})</tt>
177
+ * Constructs a text area input from the given options
178
+ * <tt>text_area_tag :username, :class => 'long'</tt>
179
+ * <tt>password_field_tag(name, options={})</tt>
180
+ * Constructs a password field input from the given options
181
+ * <tt>password_field_tag :password, :class => 'long'</tt>
182
+ * <tt>check_box_tag(name, options={})</tt>
183
+ * Constructs a checkbox input from the given options
184
+ * <tt>check_box_tag :remember_me, :checked => true</tt>
185
+ * <tt>radio_button_tag(name, options={})</tt>
186
+ * Constructs a radio button input from the given options
187
+ * <tt>radio_button_tag :gender, :value => 'male'</tt>
188
+ * <tt>select_tag(name, settings={})</tt>
189
+ * Constructs a select tag with options from the given settings
190
+ * <tt>select_tag(:favorite_color, :options => ['1', '2', '3'], :selected => '1')</tt>
191
+ * <tt>select_tag(:more_color, :options => [['label', '1'], ['label2', '2']])</tt>
192
+ * <tt>select_tag(:multiple_color, :options => [...], :multiple => true)</tt>
193
+ * <tt>file_field_tag(name, options={})</tt>
194
+ * Constructs a file field input from the given options
195
+ * <tt>file_field_tag :photo, :class => 'long'</tt>
196
+ * <tt>submit_tag(caption, options={})</tt>
197
+ * Constructs a submit button from the given options
198
+ * <tt>submit_tag "Create", :class => 'success'</tt>
199
+ * <tt>button_tag(caption, options={})</tt>
200
+ * Constructs an input (type => 'button') from the given options
201
+ * <tt>button_tag "Cancel", :class => 'clear'</tt>
202
+ * <tt>image_submit_tag(source, options={})</tt>
203
+ * Constructs an image submit button from the given options
204
+ * <tt>image_submit_tag "submit.png", :class => 'success'</tt>
205
+
206
+ === FormBuilders
207
+
208
+ Form builders are full-featured objects allowing the construction of complex object-based forms
209
+ using a simple, intuitive syntax.
210
+
211
+ A form_for using these basic fields might look like:
212
+
213
+ - form_for @user, '/register', :id => 'register' do |f|
214
+ = f.error_messages
215
+ %p
216
+ = f.label :username, :caption => "Nickname"
217
+ = f.text_field :username
218
+ %p
219
+ = f.label :email
220
+ = f.text_field :email
221
+ %p
222
+ = f.label :password
223
+ = f.password_field :password
224
+ %p
225
+ = f.label :is_admin, :caption => "Admin User?"
226
+ = f.check_box :is_admin
227
+ %p
228
+ = f.label :color, :caption => "Favorite Color?"
229
+ = f.select :color, :options => ['red', 'black']
230
+ %p
231
+ - fields_for @user.location do |location|
232
+ = location.text_field :street
233
+ = location.text_field :city
234
+ %p
235
+ = f.submit "Create", :class => 'button'
236
+
237
+ The list of defined helpers in the 'form builders' category:
238
+
239
+ * <tt>form_for(object, url, settings={}, &block)</tt>
240
+ * Constructs a form using given or default form_builder
241
+ * Supports form methods 'put' and 'delete' through hidden field
242
+ * Defaults to StandardFormBuilder but you can easily create your own!
243
+ * <tt>form_for(@user, '/register', :id => 'register') { |f| ...field-elements... }</tt>
244
+ * <tt>fields_for(object, settings={}, &block)</tt>
245
+ * Constructs fields for a given object for use in an existing form
246
+ * Defaults to StandardFormBuilder but you can easily create your own!
247
+ * <tt>fields_for @user.assignment do |assignment| ... end</tt>
248
+ * <tt>fields_for :assignment do |assigment| ... end</tt>
249
+
250
+ The following are fields provided by AbstractFormBuilder that can be used within a form_for or fields_for:
251
+
252
+ * <tt>error_messages(options={})</tt>
253
+ * Displays list html for the errors on form object
254
+ * <tt>f.errors_messages</tt>
255
+ * <tt>label(field, options={})</tt>
256
+ * <tt>f.label :name, :class => 'long'</tt>
257
+ * <tt>text_field(field, options={})</tt>
258
+ * <tt>f.text_field :username, :class => 'long'</tt>
259
+ * <tt>check_box(field, options={})</tt>
260
+ * Uses hidden field to provide a 'unchecked' value for field
261
+ * <tt>f.check_box :remember_me, :uncheck_value => 'false'</tt>
262
+ * <tt>radio_button(field, options={})</tt>
263
+ * <tt>f.radio_button :gender, :value => 'male'</tt>
264
+ * <tt>hidden_field(field, options={})</tt>
265
+ * <tt>f.hidden_field :session_id, :class => 'hidden'</tt>
266
+ * <tt>text_area(field, options={})</tt>
267
+ * <tt>f.text_area :summary, :class => 'long'</tt>
268
+ * <tt>password_field(field, options={})</tt>
269
+ * <tt>f.password_field :secret, :class => 'long'</tt>
270
+ * <tt>file_field(field, options={})</tt>
271
+ * <tt>f.file_field :photo, :class => 'long'</tt>
272
+ * <tt>select(field, options={})</tt>
273
+ * <tt>f.select(:state, :options => ['California', 'Texas', 'Wyoming'])</tt>
274
+ * <tt>f.select(:state, :collection => @states, :fields => [:name, :id])</tt>
275
+ * <tt>f.select(:state, :options => [...], :include_blank => true)</tt>
276
+ * <tt>submit(caption, options={})</tt>
277
+ * <tt>f.submit "Update", :class => 'long'</tt>
278
+ * <tt>image_submit(source, options={})</tt>
279
+ * <tt>f.image_submit "submit.png", :class => 'long'</tt>
280
+
281
+ There is also an additional StandardFormBuilder which builds on the abstract fields that can be used within a form_for.
282
+
283
+ A form_for using these standard fields might be:
284
+
285
+ - form_for @user, '/register', :id => 'register' do |f|
286
+ = f.error_messages
287
+ = f.text_field_block :name, :caption => "Full name"
288
+ = f.text_field_block :email
289
+ = f.check_box_block :remember_me
290
+ = f.select_block :fav_color, :options => ['red', 'blue']
291
+ = f.password_field_block :password
292
+ = f.submit_block "Create", :class => 'button'
293
+
294
+ and would generate this html (with each input contained in a paragraph and containing a label):
295
+
296
+ <form id="register" action="/register" method="post">
297
+ <p><label for="user_name">Full name: </label><input type="text" id="user_name" name="user[name]"></p>
298
+ ...omitted...
299
+ <p><input type="submit" value="Create" class="button"></p>
300
+ </form>
301
+
302
+ The following are fields provided by StandardFormBuilder that can be used within a form_for or fields_for:
303
+
304
+ * <tt>text_field_block(field, options={}, label_options={})</tt>
305
+ * <tt>text_field_block(:nickname, :class => 'big', :caption => "Username")</tt>
306
+ * <tt>text_area_block(field, options={}, label_options={})</tt>
307
+ * <tt>text_area_block(:about, :class => 'big')</tt>
308
+ * <tt>password_field_block(field, options={}, label_options={})</tt>
309
+ * <tt>password_field_block(:code, :class => 'big')</tt>
310
+ * <tt>file_field_block(field, options={}, label_options={})</tt>
311
+ * <tt>file_field_block(:photo, :class => 'big')</tt>
312
+ * <tt>check_box_block(field, options={}, label_options={})</tt>
313
+ * <tt>check_box_block(:remember_me, :class => 'big')</tt>
314
+ * <tt>select_block(field, options={}, label_options={})</tt>
315
+ * <tt>select_block(:country, :option => ['USA', 'Canada'])</tt>
316
+ * <tt>submit_block(caption, options={})</tt>
317
+ * <tt>submit_block(:username, :class => 'big')</tt>
318
+ * <tt>image_submit_block(source, options={})</tt>
319
+ * <tt>image_submit_block('submit.png', :class => 'big')</tt>
320
+
321
+ You can also easily build your own FormBuilder which allows for customized fields and behavior:
322
+
323
+ class MyCustomFormBuilder < AbstractFormBuilder
324
+ # Here we have access to a number of useful variables
325
+ #
326
+ # * view_context (use this to invoke any helpers)(ex. view_context.hidden_field_tag(...))
327
+ # * object (the record for this form) (ex. object.valid?)
328
+ # * object_name (object's underscored type) (ex. object_name => 'admin_user')
329
+ #
330
+ # We also have access to self.field_types => [:text_field, :text_area, ...]
331
+ # In addition, we have access to all the existing field tag helpers (text_field, hidden_field, file_field, ...)
332
+ end
333
+
334
+ Once a custom builder is defined, any call to form_for can use the new builder:
335
+
336
+ - form_for @user, '/register', :builder => MyCustomFormBuilder, :id => 'register' do |f|
337
+ ...fields here...
338
+
339
+ === Format Helpers
340
+
341
+ Format helpers are several useful utilities for manipulating the format of text to achieve a goal.
342
+ The format helper <tt>escape_html</tt> is also aliased as <tt>h</tt> and <tt>sanitize_html</tt>
343
+
344
+ The escape_html function is for taking an html string and escaping certain characters.
345
+ <tt>escape_html</tt> will escape ampersands, brackets and quotes to their HTML/XML entities. This is useful
346
+ to sanitize user content before displaying this on a template.
347
+
348
+ escape_html('<hello>&<goodbye>') # => &lt;hello&gt;&amp;&lt;goodbye&gt;
349
+
350
+ Format helpers also includes a number of useful text manipulation functions such as <tt>simple_format</tt>, and <tt>truncate</tt>.
351
+
352
+ simple_format("hello\nworld") # => "<p>hello<br/>world</p>"
353
+ truncate("Once upon a time in a world far far away", :length => 8) => "Once upon..."
354
+
355
+ The list of defined helpers in the 'format helpers' category:
356
+
357
+ * <tt>simple_format(text, html_options)</tt>
358
+ * Returns text transformed into HTML using simple formatting rules.
359
+ * <tt>simple_format("hello\nworld")</tt> => "<p>hello<br/>world</p>"
360
+ * <tt>truncate(text, *args)</tt>
361
+ * Truncates a given text after a given :length if text is longer than :length (defaults to 30).
362
+ * <tt>truncate("Once upon a time in a world far far away", :length => 8)</tt> => "Once upon..."
363
+ * <tt>escape_html</tt> (alias <tt>h</tt> and <tt>h!</tt>)
364
+ * (from RackUtils) Escape ampersands, brackets and quotes to their HTML/XML entities.
365
+
366
+ == Copyright
367
+
368
+ Copyright (c) 2009 Daniel Neighman. See LICENSE for details.
369
+
data/Rakefile ADDED
@@ -0,0 +1,57 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "any_view"
8
+ gem.summary = %Q{View helpers designed to work just about anywhere}
9
+ gem.description = %Q{View helpers with an absolute minimum of requirements}
10
+ gem.email = "has.sox@gmail.com"
11
+ gem.homepage = "http://github.com/hassox/any_view"
12
+ gem.authors = ["Daniel Neighman"]
13
+ gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
14
+ gem.add_development_dependency "haml", ">= 2.2.1"
15
+ gem.add_development_dependency "shoulda", ">= 0"
16
+ gem.add_development_dependency "rack-test", ">= 0.5.0"
17
+ gem.add_development_dependency "webrat", ">= 0.5.1"
18
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
19
+ end
20
+ Jeweler::GemcutterTasks.new
21
+ rescue LoadError
22
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
23
+ end
24
+
25
+ require 'rake/testtask'
26
+ Rake::TestTask.new(:test) do |test|
27
+ test.libs << 'lib' << 'test'
28
+ test.pattern = 'test/**/test_*.rb'
29
+ test.verbose = true
30
+ end
31
+
32
+ begin
33
+ require 'rcov/rcovtask'
34
+ Rcov::RcovTask.new do |test|
35
+ test.libs << 'test'
36
+ test.pattern = 'test/**/test_*.rb'
37
+ test.verbose = true
38
+ end
39
+ rescue LoadError
40
+ task :rcov do
41
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
42
+ end
43
+ end
44
+
45
+ task :test => :check_dependencies
46
+
47
+ task :default => :test
48
+
49
+ require 'rake/rdoctask'
50
+ Rake::RDocTask.new do |rdoc|
51
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
52
+
53
+ rdoc.rdoc_dir = 'rdoc'
54
+ rdoc.title = "any_view #{version}"
55
+ rdoc.rdoc_files.include('README*')
56
+ rdoc.rdoc_files.include('lib/**/*.rb')
57
+ end
@@ -0,0 +1,103 @@
1
+ module AnyView
2
+ module Helpers
3
+ module AssetTagHelpers
4
+ MAIL_ATTRIBUTES = [:cc, :bcc, :subject, :body]
5
+
6
+ # Creates a link element with given name, url and options
7
+ # link_to("/url", :class => "foo"){ "link text" }
8
+ # link_to 'click me', '/dashboard', :class => 'linky'
9
+ def link_to(*args, &block)
10
+ options = args.extract_options!
11
+ text, url = args
12
+ if url.nil?
13
+ url = text
14
+ text = capture_content(&block)
15
+ end
16
+ options.reverse_merge!(:href => url)
17
+ options[:content] = text
18
+ result = tag(:a, options)
19
+ block.nil? ? result : concat_content(result)
20
+ end
21
+
22
+ # Creates a mail link element with given name and caption
23
+ # mail_to "me@demo.com" => <a href="mailto:me@demo.com">me@demo.com</a>
24
+ # mail_to "me@demo.com", "My Email" => <a href="mailto:me@demo.com">My Email</a>
25
+ def mail_to(email, caption=nil, options={})
26
+ mail_options, options = options.partition{|k,v| MAIL_ATTRIBUTES.include?(k)}
27
+ mail_options, options = Hash[mail_options], Hash[options]
28
+ mail_query = Rack::Utils.build_query(mail_options).gsub(/\+/, '%20').gsub('%40', '@')
29
+ mail_href = "mailto:#{email}"; mail_href << "?#{mail_query}" if mail_query.present?
30
+ link_to (caption || email), mail_href, options
31
+ end
32
+
33
+ # Creates an image element with given url and options
34
+ # image_tag('icons/avatar.png')
35
+ def image_tag(url, options={})
36
+ options.reverse_merge!(:src => image_path(url))
37
+ tag(:img, options)
38
+ end
39
+
40
+ # Returns a stylesheet link tag for the sources specified as arguments
41
+ # stylesheet_link_tag 'style', 'application', 'layout'
42
+ def stylesheet_link_tag(*sources)
43
+ options = sources.extract_options!.symbolize_keys
44
+ sources.collect { |sheet| stylesheet_tag(sheet, options) }.join("\n")
45
+ end
46
+
47
+ # javascript_include_tag 'application', 'special'
48
+ def javascript_include_tag(*sources)
49
+ options = sources.extract_options!.symbolize_keys
50
+ sources.collect { |script| javascript_tag(script, options) }.join("\n")
51
+ end
52
+
53
+ # Returns the path to the image, either relative or absolute
54
+ def image_path(src)
55
+ src.gsub!(/\s/, '')
56
+ src =~ %r{^\s*(/|http)} ? src : uri_root_path('images', src)
57
+ end
58
+
59
+ protected
60
+
61
+ # stylesheet_tag('style', :media => 'screen')
62
+ def stylesheet_tag(source, options={})
63
+ options = options.dup.reverse_merge!(:href => stylesheet_path(source), :media => 'screen', :rel => 'stylesheet', :type => 'text/css')
64
+ tag(:link, options)
65
+ end
66
+
67
+ # javascript_tag 'application', :src => '/javascripts/base/application.js'
68
+ def javascript_tag(source, options={})
69
+ options = options.dup.reverse_merge!(:src => javascript_path(source), :type => 'text/javascript', :content => "")
70
+ tag(:script, options)
71
+ end
72
+
73
+ # Returns the javascript_path appending the default javascripts path if necessary
74
+ def javascript_path(source)
75
+ return source if source =~ /^http/
76
+ source.gsub!(/\.js$/, '')
77
+ source_name = source; source_name << ".js" unless source =~ /\.js\w{2,4}$/
78
+ result_path = source_name if source =~ %r{^/} # absolute path
79
+ result_path ||= uri_root_path("javascripts", source_name)
80
+ stamp = File.exist?(result_path) ? File.mtime(result_path) : Time.now.to_i
81
+ "#{result_path}?#{stamp}"
82
+ end
83
+
84
+ # Returns the stylesheet_path appending the default stylesheets path if necessary
85
+ def stylesheet_path(source)
86
+ return source if source =~ /^http/
87
+ source.gsub!(/\.css$/, '')
88
+ source_name = source; source_name << ".css" unless source =~ /\.css$/
89
+ result_path = source_name if source =~ %r{^/} # absolute path
90
+ result_path ||= uri_root_path("stylesheets", source_name)
91
+ stamp = File.exist?(result_path) ? File.mtime(result_path) : Time.now.to_i
92
+ "#{result_path}?#{stamp}"
93
+ end
94
+
95
+ # Returns the uri root of the application, defaulting to '/'
96
+ # @example uri_root('javascripts')
97
+ def uri_root_path(*paths)
98
+ root_uri = uri_root if self.respond_to?(:uri_root)
99
+ File.join(root_uri || '/', *paths)
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,7 @@
1
+ unless Array.method_defined?(:extract_options!)
2
+ class Array
3
+ def extract_options!
4
+ last.is_a?(Hash) ? pop : {}
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,41 @@
1
+ class Hash
2
+ unless method_defined?(:reverse_merge!)
3
+ def reverse_merge!(other = {})
4
+ other.each{|k,v| self[k] ||= v}
5
+ self
6
+ end
7
+ end
8
+
9
+ unless method_defined?(:slice!)
10
+ def slice!(*keys)
11
+ keys = keys.flatten
12
+ out = {}
13
+ keys.each{|k| out[k] = self[k]}
14
+ replace out
15
+ self
16
+ end
17
+
18
+ def slice(*keys)
19
+ out = dup
20
+ out.slice!(*keys)
21
+ end
22
+ end
23
+
24
+ unless method_defined?(:symbolize_keys)
25
+ def symbolize_keys
26
+ out = dup
27
+ out.symbolize_keys!
28
+ end
29
+ end
30
+
31
+ unless method_defined?(:symbolize_keys!)
32
+ def symbolize_keys!
33
+ symbolizable_keys = []
34
+ keys.each{|k| symbolizable_keys << k if k.respond_to?(:to_sym) && !k.is_a?(Symbol)}
35
+ symbolizable_keys.each do |k|
36
+ self[k.to_sym] = delete(k)
37
+ end
38
+ self
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,17 @@
1
+ class String
2
+ unless method_defined?(:titleize)
3
+ def titleize
4
+ gsub("_", " ").gsub(/\b('?[a-z])/){$1.upcase}
5
+ end
6
+ end
7
+
8
+ unless method_defined?(:underscore)
9
+ def underscore
10
+ gsub(/::/, '/').
11
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
12
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
13
+ gsub("-", "_").
14
+ downcase
15
+ end
16
+ end
17
+ end