A skeleton web application configured to use Sinatra and ActiveRecord
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Import helpers from sinatra_more v0.3.43

These have been modified to integrate Rack::Csrf tokens and other
minor changes, so just keep them in the tree.

+1146
+4
lib/app.rb
··· 134 134 require f 135 135 end 136 136 137 + # and sinatra_more form and render helpers 138 + require "#{App.root}/lib/sinatra_more/markup_plugin" 139 + require "#{App.root}/lib/sinatra_more/render_plugin" 140 + 137 141 # and controllers, binding each's helper 138 142 ( 139 143 [ "#{App.root}/app/controllers/application_controller.rb" ] +
+41
lib/sinatra_more/markup_plugin.rb
··· 1 + # 2 + # sinatra_more 3 + # Copyright (c) 2009 Nathan Esquenazi 4 + # 5 + # Permission is hereby granted, free of charge, to any person obtaining 6 + # a copy of this software and associated documentation files (the 7 + # "Software"), to deal in the Software without restriction, including 8 + # without limitation the rights to use, copy, modify, merge, publish, 9 + # distribute, sublicense, and/or sell copies of the Software, and to 10 + # permit persons to whom the Software is furnished to do so, subject to 11 + # the following conditions: 12 + # 13 + # The above copyright notice and this permission notice shall be 14 + # included in all copies or substantial portions of the Software. 15 + # 16 + # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 + # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 + # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 + # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 + # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 + # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 + # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 + # 24 + 25 + require File.dirname(__FILE__) + '/support_lite' 26 + require File.dirname(__FILE__) + '/markup_plugin/form_builder/abstract_form_builder' 27 + require File.dirname(__FILE__) + '/markup_plugin/form_builder/standard_form_builder' 28 + Dir[File.dirname(__FILE__) + '/markup_plugin/*.rb'].each {|file| load file } 29 + 30 + module SinatraMore 31 + module MarkupPlugin 32 + def self.registered(app) 33 + app.set :default_builder, 'StandardFormBuilder' 34 + app.helpers OutputHelpers 35 + app.helpers TagHelpers 36 + app.helpers AssetTagHelpers 37 + app.helpers FormHelpers 38 + app.helpers FormatHelpers 39 + end 40 + end 41 + end
+129
lib/sinatra_more/markup_plugin/asset_tag_helpers.rb
··· 1 + # 2 + # sinatra_more 3 + # Copyright (c) 2009 Nathan Esquenazi 4 + # 5 + # Permission is hereby granted, free of charge, to any person obtaining 6 + # a copy of this software and associated documentation files (the 7 + # "Software"), to deal in the Software without restriction, including 8 + # without limitation the rights to use, copy, modify, merge, publish, 9 + # distribute, sublicense, and/or sell copies of the Software, and to 10 + # permit persons to whom the Software is furnished to do so, subject to 11 + # the following conditions: 12 + # 13 + # The above copyright notice and this permission notice shall be 14 + # included in all copies or substantial portions of the Software. 15 + # 16 + # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 + # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 + # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 + # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 + # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 + # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 + # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 + # 24 + 25 + module SinatraMore 26 + module AssetTagHelpers 27 + 28 + # Creates a div to display the flash of given type if it exists 29 + # flash_tag(:notice, :class => 'flash', :id => 'flash-notice') 30 + def flash_tag(kind, options={}) 31 + flash_text = flash[kind] 32 + return '' if flash_text.blank? 33 + options.reverse_merge!(:class => 'flash') 34 + content_tag(:div, flash_text, options) 35 + end 36 + 37 + # Creates a link element with given name, url and options 38 + # link_to 'click me', '/dashboard', :class => 'linky' 39 + # link_to('/dashboard', :class => 'blocky') do ... end 40 + # parameters: name, url='javascript:void(0)', options={}, &block 41 + def link_to(*args, &block) 42 + if block_given? 43 + url, options = (args[0] || 'javascript:void(0);'), (args[1] || {}) 44 + options.reverse_merge!(:href => url) 45 + link_content = capture_html(&block) 46 + result_link = content_tag(:a, link_content, options) 47 + block_is_template?(block) ? concat_content(result_link) : result_link 48 + else 49 + name, url, options = args.first, (args[1] || 'javascript:void(0);'), (args[2] || {}) 50 + options.reverse_merge!(:href => url) 51 + content_tag(:a, name, options) 52 + end 53 + end 54 + 55 + # Creates a mail link element with given name and caption 56 + # mail_to "me@demo.com" => <a href="mailto:me@demo.com">me@demo.com</a> 57 + # mail_to "me@demo.com", "My Email" => <a href="mailto:me@demo.com">My Email</a> 58 + def mail_to(email, caption=nil, mail_options={}) 59 + html_options = mail_options.slice!(:cc, :bcc, :subject, :body) 60 + mail_query = Rack::Utils.build_query(mail_options).gsub(/\+/, '%20').gsub('%40', '@') 61 + mail_href = "mailto:#{email}"; mail_href << "?#{mail_query}" if mail_query.present? 62 + link_to (caption || email), mail_href, html_options 63 + end 64 + 65 + # Creates a meta element with the content and given options 66 + # meta_tag "weblog,news", :name => "keywords" => <meta name="keywords" content="weblog,news"> 67 + # meta_tag "text/html; charset=UTF-8", :http-equiv => "Content-Type" => <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 68 + def meta_tag(content, options={}) 69 + options.reverse_merge!("content" => content) 70 + tag(:meta, options) 71 + end 72 + 73 + # Creates an image element with given url and options 74 + # image_tag('icons/avatar.png') 75 + def image_tag(url, options={}) 76 + options.reverse_merge!(:src => image_path(url)) 77 + tag(:img, options) 78 + end 79 + 80 + # Returns a stylesheet link tag for the sources specified as arguments 81 + # stylesheet_link_tag 'style', 'application', 'layout' 82 + def stylesheet_link_tag(*sources) 83 + options = sources.extract_options!.symbolize_keys 84 + sources.collect { |sheet| stylesheet_tag(sheet, options) }.join("\n") 85 + end 86 + 87 + # javascript_include_tag 'application', 'special' 88 + def javascript_include_tag(*sources) 89 + options = sources.extract_options!.symbolize_keys 90 + sources.collect { |script| javascript_tag(script, options) }.join("\n") 91 + end 92 + 93 + # Returns the path to the image, either relative or absolute 94 + def image_path(src) 95 + src.gsub!(/\s/, '') 96 + src =~ %r{^\s*(/|http)} ? src : File.join('/images', src) 97 + end 98 + 99 + protected 100 + 101 + # stylesheet_tag('style', :media => 'screen') 102 + def stylesheet_tag(source, options={}) 103 + options = options.dup.reverse_merge!(:href => stylesheet_path(source), :media => 'screen', :rel => 'stylesheet', :type => 'text/css') 104 + tag(:link, options) 105 + end 106 + 107 + # javascript_tag 'application', :src => '/javascripts/base/application.js' 108 + def javascript_tag(source, options={}) 109 + options = options.dup.reverse_merge!(:src => javascript_path(source), :type => 'text/javascript', :content => "") 110 + tag(:script, options) 111 + end 112 + 113 + def javascript_path(source) 114 + return source if source =~ /^http/ 115 + result_path = "/javascripts/#{source.gsub(/.js$/, '')}" 116 + result_path << ".js" unless source =~ /\.js\w{2,4}$/ 117 + stamp = File.exist?(result_path) ? File.mtime(result_path) : Time.now.to_i 118 + "#{result_path}?#{stamp}" 119 + end 120 + 121 + def stylesheet_path(source) 122 + return source if source =~ /^http/ 123 + result_path = "/stylesheets/#{source.gsub(/.css$/, '')}" 124 + result_path << ".css" unless source =~ /\.css\w{2,4}$/ 125 + stamp = File.exist?(result_path) ? File.mtime(result_path) : Time.now.to_i 126 + "#{result_path}?#{stamp}" 127 + end 128 + end 129 + end
+157
lib/sinatra_more/markup_plugin/form_builder/abstract_form_builder.rb
··· 1 + # 2 + # sinatra_more 3 + # Copyright (c) 2009 Nathan Esquenazi 4 + # 5 + # Permission is hereby granted, free of charge, to any person obtaining 6 + # a copy of this software and associated documentation files (the 7 + # "Software"), to deal in the Software without restriction, including 8 + # without limitation the rights to use, copy, modify, merge, publish, 9 + # distribute, sublicense, and/or sell copies of the Software, and to 10 + # permit persons to whom the Software is furnished to do so, subject to 11 + # the following conditions: 12 + # 13 + # The above copyright notice and this permission notice shall be 14 + # included in all copies or substantial portions of the Software. 15 + # 16 + # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 + # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 + # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 + # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 + # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 + # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 + # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 + # 24 + 25 + class AbstractFormBuilder 26 + attr_accessor :template, :object 27 + 28 + def initialize(template, object) 29 + @template = template 30 + @object = build_object(object) 31 + raise "FormBuilder template must be initialized!" unless template 32 + raise "FormBuilder object must be not be nil value. If there's no object, use a symbol instead! (i.e :user)" unless object 33 + end 34 + 35 + # f.error_messages 36 + def error_messages(options={}) 37 + @template.error_messages_for(@object, options) 38 + end 39 + 40 + # f.label :username, :caption => "Nickname" 41 + def label(field, options={}) 42 + options.reverse_merge!(:caption => "#{field.to_s.titleize}: ") 43 + @template.label_tag(field_id(field), options) 44 + end 45 + 46 + # f.hidden_field :session_id, :value => "45" 47 + def hidden_field(field, options={}) 48 + options.reverse_merge!(:value => field_value(field), :id => field_id(field)) 49 + @template.hidden_field_tag field_name(field), options 50 + end 51 + 52 + # f.text_field :username, :value => "(blank)", :id => 'username' 53 + def text_field(field, options={}) 54 + options.reverse_merge!(:value => field_value(field), :id => field_id(field)) 55 + @template.text_field_tag field_name(field), options 56 + end 57 + 58 + # f.text_area :summary, :value => "(enter summary)", :id => 'summary' 59 + def text_area(field, options={}) 60 + options.reverse_merge!(:value => field_value(field), :id => field_id(field)) 61 + @template.text_area_tag field_name(field), options 62 + end 63 + 64 + # f.password_field :password, :id => 'password' 65 + def password_field(field, options={}) 66 + options.reverse_merge!(:value => field_value(field), :id => field_id(field)) 67 + @template.password_field_tag field_name(field), options 68 + end 69 + 70 + # f.select :color, :options => ['red', 'green'], :include_blank => true 71 + # f.select :color, :collection => @colors, :fields => [:name, :id] 72 + def select(field, options={}) 73 + options.reverse_merge!(:id => field_id(field), :selected => field_value(field)) 74 + @template.select_tag field_name(field), options 75 + end 76 + 77 + # f.check_box :remember_me, :value => 'true', :uncheck_value => '0' 78 + def check_box(field, options={}) 79 + unchecked_value = options.delete(:uncheck_value) || '0' 80 + options.reverse_merge!(:id => field_id(field), :value => '1') 81 + options.merge!(:checked => true) if values_matches_field?(field, options[:value]) 82 + html = hidden_field(field, :value => unchecked_value, :id => nil) 83 + html << @template.check_box_tag(field_name(field), options) 84 + end 85 + 86 + # f.radio_button :gender, :value => 'male' 87 + def radio_button(field, options={}) 88 + options.reverse_merge!(:id => field_id(field, options[:value])) 89 + options.merge!(:checked => true) if values_matches_field?(field, options[:value]) 90 + @template.radio_button_tag field_name(field), options 91 + end 92 + 93 + # f.file_field :photo, :class => 'avatar' 94 + def file_field(field, options={}) 95 + options.reverse_merge!(:id => field_id(field)) 96 + @template.file_field_tag field_name(field), options 97 + end 98 + 99 + # f.submit "Update", :class => 'large' 100 + def submit(caption="Submit", options={}) 101 + @template.submit_tag caption, options 102 + end 103 + 104 + # f.simage_submitubmit "buttons/submit.png", :class => 'large' 105 + def image_submit(source, options={}) 106 + @template.image_submit_tag source, options 107 + end 108 + 109 + protected 110 + 111 + # Returns the known field types for a formbuilder 112 + def self.field_types 113 + [:hidden_field, :text_field, :text_area, :password_field, :file_field, :radio_button, :check_box, :select] 114 + end 115 + 116 + # Returns the object's models name 117 + # => user_assignment 118 + def object_name 119 + object.is_a?(Symbol) ? object : object.class.to_s.underscore.gsub('/', '-') 120 + end 121 + 122 + # Returns true if the value matches the value in the field 123 + # field_has_value?(:gender, 'male') 124 + def values_matches_field?(field, value) 125 + value.present? && (field_value(field).to_s == value.to_s || field_value(field).to_s == 'true') 126 + end 127 + 128 + # Returns the value for the object's field 129 + # field_value(:username) => "Joey" 130 + def field_value(field) 131 + @object && @object.respond_to?(field) ? @object.send(field) : "" 132 + end 133 + 134 + # Returns the name for the given field 135 + # field_name(:username) => "user[username]" 136 + def field_name(field) 137 + "#{object_name}[#{field}]" 138 + end 139 + 140 + # Returns the id for the given field 141 + # field_id(:username) => "user_username" 142 + # field_id(:gender, :male) => "user_gender_male" 143 + def field_id(field, value=nil) 144 + value.blank? ? "#{object_name}_#{field}" : "#{object_name}_#{field}_#{value}" 145 + end 146 + 147 + # explicit_object is either a symbol or a record 148 + # Returns a new record of the type specified in the object 149 + def build_object(object_or_symbol) 150 + object_or_symbol.is_a?(Symbol) ? object_class(object_or_symbol).new : object_or_symbol 151 + end 152 + 153 + # Returns the class type for the given object 154 + def object_class(explicit_object) 155 + explicit_object.is_a?(Symbol) ? explicit_object.to_s.classify.constantize : explicit_object.class 156 + end 157 + end
+55
lib/sinatra_more/markup_plugin/form_builder/standard_form_builder.rb
··· 1 + # 2 + # sinatra_more 3 + # Copyright (c) 2009 Nathan Esquenazi 4 + # 5 + # Permission is hereby granted, free of charge, to any person obtaining 6 + # a copy of this software and associated documentation files (the 7 + # "Software"), to deal in the Software without restriction, including 8 + # without limitation the rights to use, copy, modify, merge, publish, 9 + # distribute, sublicense, and/or sell copies of the Software, and to 10 + # permit persons to whom the Software is furnished to do so, subject to 11 + # the following conditions: 12 + # 13 + # The above copyright notice and this permission notice shall be 14 + # included in all copies or substantial portions of the Software. 15 + # 16 + # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 + # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 + # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 + # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 + # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 + # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 + # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 + # 24 + 25 + class StandardFormBuilder < AbstractFormBuilder 26 + 27 + # text_field_block(:username, { :class => 'long' }, { :class => 'wide-label' }) 28 + # text_area_block(:summary, { :class => 'long' }, { :class => 'wide-label' }) 29 + # password_field_block(:password, { :class => 'long' }, { :class => 'wide-label' }) 30 + # file_field_block(:photo, { :class => 'long' }, { :class => 'wide-label' }) 31 + # check_box_block(:remember_me, { :class => 'long' }, { :class => 'wide-label' }) 32 + # select_block(:color, :options => ['green', 'black']) 33 + (self.field_types - [ :hidden_field, :radio_button ]).each do |field_type| 34 + class_eval <<-EOF 35 + def #{field_type}_block(field, options={}, label_options={}) 36 + label_options.reverse_merge!(:caption => options.delete(:caption)) if options[:caption] 37 + field_html = label(field, label_options) 38 + field_html << #{field_type}(field, options) 39 + @template.content_tag(:p, field_html) 40 + end 41 + EOF 42 + end 43 + 44 + # submit_block("Update") 45 + def submit_block(caption, options={}) 46 + submit_html = self.submit(caption, options) 47 + @template.content_tag(:p, submit_html) 48 + end 49 + 50 + # image_submit_block("submit.png") 51 + def image_submit_block(source, options={}) 52 + submit_html = self.image_submit(source, options) 53 + @template.content_tag(:p, submit_html) 54 + end 55 + end
+299
lib/sinatra_more/markup_plugin/form_helpers.rb
··· 1 + # 2 + # sinatra_more 3 + # Copyright (c) 2009 Nathan Esquenazi 4 + # 5 + # Permission is hereby granted, free of charge, to any person obtaining 6 + # a copy of this software and associated documentation files (the 7 + # "Software"), to deal in the Software without restriction, including 8 + # without limitation the rights to use, copy, modify, merge, publish, 9 + # distribute, sublicense, and/or sell copies of the Software, and to 10 + # permit persons to whom the Software is furnished to do so, subject to 11 + # the following conditions: 12 + # 13 + # The above copyright notice and this permission notice shall be 14 + # included in all copies or substantial portions of the Software. 15 + # 16 + # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 + # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 + # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 + # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 + # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 + # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 + # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 + # 24 + 25 + require_relative "./form_builder/abstract_form_builder" 26 + require_relative "./form_builder/standard_form_builder" 27 + 28 + module SinatraMore 29 + module FormHelpers 30 + # Constructs a form for object using given or default form_builder 31 + # form_for :user, '/register' do |f| ... end 32 + # form_for @user, '/register', :id => 'register' do |f| ... end 33 + def form_for(object, url, settings={}, &block) 34 + builder_class = configured_form_builder_class(settings[:builder]) 35 + form_html = capture_html(builder_class.new(self, object), &block) 36 + form_tag(url, settings) { form_html } 37 + end 38 + 39 + # Constructs form fields for an object using given or default form_builder 40 + # Used within an existing form to allow alternate objects within one form 41 + # fields_for @user.assignment do |assignment| ... end 42 + # fields_for :assignment do |assigment| ... end 43 + def fields_for(object, settings={}, &block) 44 + builder_class = configured_form_builder_class(settings[:builder]) 45 + fields_html = capture_html(builder_class.new(self, object), &block) 46 + concat_content fields_html 47 + end 48 + 49 + # Constructs a form without object based on options 50 + # form_tag '/register' do ... end 51 + def form_tag(url, options={}, &block) 52 + options.reverse_merge!(:method => 'post', :action => url) 53 + if options.delete(:multipart) 54 + options[:enctype] = "multipart/form-data" 55 + end 56 + inner_form_html = hidden_form_method_field(options[:method]) + 57 + capture_html(&block) 58 + if options[:method].to_sym != :get 59 + inner_form_html = hidden_field_tag(Rack::Csrf.field, 60 + :value => Rack::Csrf.csrf_token(env)) + inner_form_html 61 + end 62 + concat_content content_tag('form', inner_form_html, options) 63 + end 64 + 65 + # Constructs a field_set to group fields with given options 66 + # field_set_tag("Office", :class => 'office-set') 67 + # parameters: legend_text=nil, options={} 68 + def field_set_tag(*args, &block) 69 + options = args.extract_options! 70 + legend_text = args[0].is_a?(String) ? args.first : nil 71 + legend_html = legend_text.blank? ? '' : content_tag(:legend, legend_text) 72 + field_set_content = legend_html + capture_html(&block) 73 + concat_content content_tag('fieldset', field_set_content, options) 74 + end 75 + 76 + # Constructs list html for the errors for a given object 77 + # error_messages_for @user 78 + def error_messages_for(record, options={}) 79 + if record.blank? || record.errors.none? 80 + return "" 81 + end 82 + options.reverse_merge!(:header_message => 83 + "The #{record.class.to_s.downcase} could not be saved!") 84 + error_messages = record.errors.full_messages 85 + error_items = error_messages.collect{|er| content_tag(:li, er) }. 86 + join("\n") 87 + error_html = content_tag(:p, options.delete(:header_message)) 88 + error_html << content_tag(:ul, error_items, :class => 'errors-list') 89 + content_tag(:div, error_html, :class => 'field-errors') 90 + end 91 + 92 + # Constructs a label tag from the given options 93 + # label_tag :username, :class => 'long-label' 94 + # label_tag :username, :class => 'long-label' do ... end 95 + def label_tag(name, options={}, &block) 96 + options.reverse_merge!(:caption => "#{name.to_s.titleize}: ", 97 + :for => name) 98 + caption_text = options.delete(:caption) 99 + if block_given? # label with inner content 100 + label_content = caption_text + capture_html(&block) 101 + concat_content(content_tag(:label, label_content, options)) 102 + else # regular label 103 + content_tag(:label, caption_text, options) 104 + end 105 + end 106 + 107 + # Constructs a hidden field input from the given options 108 + # hidden_field_tag :session_key, :value => "__secret__" 109 + def hidden_field_tag(name, options={}) 110 + options.reverse_merge!(:name => name) 111 + input_tag(:hidden, options) 112 + end 113 + 114 + # Constructs a text field input from the given options 115 + # text_field_tag :username, :class => 'long' 116 + def text_field_tag(name, options={}) 117 + options.reverse_merge!(:name => name) 118 + input_tag(:text, options) 119 + end 120 + 121 + # Constructs a text area input from the given options 122 + # text_area_tag :username, :class => 'long', :value => "Demo?" 123 + def text_area_tag(name, options={}) 124 + options.reverse_merge!(:name => name) 125 + content_tag(:textarea, options.delete(:value).to_s, options) 126 + end 127 + 128 + # Constructs a password field input from the given options 129 + # password_field_tag :password, :class => 'long' 130 + def password_field_tag(name, options={}) 131 + options.reverse_merge!(:name => name) 132 + input_tag(:password, options) 133 + end 134 + 135 + # Constructs a check_box from the given options 136 + # options = [['caption', 'value'], ['Green', 'green1'], 137 + # ['Blue', 'blue1'], ['Black', "black1"]] 138 + # options = ['option', 'red', 'yellow' ] 139 + # select_tag(:favorite_color, :options => ['red', 'yellow'], 140 + # :selected => 'green1') 141 + # select_tag(:country, :collection => @countries, 142 + # :fields => [:name, :code]) 143 + def select_tag(name, options={}) 144 + options.reverse_merge!(:name => name) 145 + collection, fields = options.delete(:collection), options.delete(:fields) 146 + if collection 147 + options[:options] = options_from_collection(collection, fields) 148 + end 149 + if groups = options.delete(:groups) 150 + selected = options.delete(:selected) 151 + select_options_html = grouped_options_for_select(groups, selected) 152 + if options.delete(:include_blank) 153 + select_options_html = options_for_select([ "" ], selected) + 154 + select_options_html 155 + end 156 + else 157 + if options.delete(:include_blank) 158 + options[:options].unshift('') 159 + end 160 + select_options_html = options_for_select(options.delete(:options), 161 + options.delete(:selected)) 162 + end 163 + if options[:multiple] 164 + options.merge!(:name => "#{options[:name]}[]") 165 + end 166 + content_tag(:select, select_options_html, options) 167 + end 168 + 169 + # Constructs a check_box from the given options 170 + # check_box_tag :remember_me, :value => 'Yes' 171 + def check_box_tag(name, options={}) 172 + options.reverse_merge!(:name => name, :value => '1') 173 + input_tag(:checkbox, options) 174 + end 175 + 176 + # Constructs a radio_button from the given options 177 + # radio_button_tag :remember_me, :value => 'true' 178 + def radio_button_tag(name, options={}) 179 + options.reverse_merge!(:name => name) 180 + input_tag(:radio, options) 181 + end 182 + 183 + # Constructs a file field input from the given options 184 + # file_field_tag :photo, :class => 'long' 185 + def file_field_tag(name, options={}) 186 + options.reverse_merge!(:name => name) 187 + input_tag(:file, options) 188 + end 189 + 190 + # Constructs a submit button from the given options 191 + # submit_tag "Create", :class => 'success' 192 + def submit_tag(caption="Submit", options={}) 193 + options.reverse_merge!(:value => caption) 194 + input_tag(:submit, options) 195 + end 196 + 197 + # Constructs a button input from the given options 198 + # button_tag "Cancel", :class => 'clear' 199 + def button_tag(caption, options = {}, &block) 200 + options.reverse_merge!(:value => caption) 201 + content_tag(:button, caption, options, &block) 202 + end 203 + 204 + # Constructs a submit button from the given options 205 + # submit_tag "Create", :class => 'success' 206 + def image_submit_tag(source, options = {}) 207 + options.reverse_merge!(:src => image_path(source)) 208 + input_tag(:image, options) 209 + end 210 + 211 + protected 212 + 213 + # Returns an array of option items for a select field based on the given 214 + # collection fields is an array containing the fields to display from each 215 + # item in the collection 216 + def options_from_collection(collection, fields) 217 + if collection.blank? 218 + return '' 219 + end 220 + collection.collect{|item| [ item.send(fields.first), 221 + item.send(fields.last) ] } 222 + end 223 + 224 + # Returns the options tags for a select based on the given option items 225 + def options_for_select(option_items, selected_values = []) 226 + if option_items.blank? 227 + return '' 228 + end 229 + if !selected_values.is_a?(Array) 230 + selected_values = [selected_values].compact 231 + end 232 + option_items.collect{|caption, value| 233 + value ||= caption 234 + selected = selected_values.find{|v| 235 + v.to_s.match(/^(#{value}|#{caption})$/) 236 + } 237 + content_tag(:option, caption, :value => value, :selected => !!selected) 238 + }.join("\n") 239 + end 240 + 241 + # Returns the options tags for a select based on the given option items 242 + def grouped_options_for_select(grouped_option_items, selected_values = []) 243 + if grouped_option_items.blank? 244 + return '' 245 + end 246 + if !selected_values.is_a?(Array) 247 + selected_values = [selected_values].compact 248 + end 249 + 250 + grouped_option_items.collect{|group| 251 + content_tag(:optgroup, 252 + group[1].collect{|caption, value| 253 + value ||= caption 254 + selected = selected_values.find{|v| 255 + v.to_s.match(/^(#{value}|#{caption})$/) 256 + } 257 + content_tag(:option, caption, :value => value, 258 + :selected => !!selected) 259 + }.join("\n"), 260 + :label => group[0]) 261 + }.join("\n") 262 + end 263 + 264 + # returns the hidden method field for 'put' and 'delete' forms 265 + # Only 'get' and 'post' are allowed within browsers; 266 + # 'put' and 'delete' are just specified using hidden fields with form 267 + # action still 'put'. 268 + # hidden_form_method_field('delete') => 269 + # <input name="_method" value="delete" /> 270 + def hidden_form_method_field(desired_method) 271 + if desired_method.to_s.match(/get|post/) 272 + return '' 273 + end 274 + original_method = desired_method.dup 275 + desired_method.replace('post') 276 + hidden_field_tag(:_method, :value => original_method) 277 + end 278 + 279 + # Returns the FormBuilder class to use based on all available setting 280 + # sources 281 + # If explicitly defined, returns that, otherwise returns defaults 282 + # configured_form_builder_class(nil) => StandardFormBuilder 283 + def configured_form_builder_class(explicit_builder = nil) 284 + default_builder = if self.respond_to?(:settings) && 285 + self.settings.respond_to?(:default_builder) 286 + self.settings.default_builder 287 + else 288 + nil 289 + end 290 + 291 + configured_builder = explicit_builder || default_builder || 292 + 'StandardFormBuilder' 293 + if configured_builder.is_a?(String) 294 + configured_builder = configured_builder.constantize 295 + end 296 + configured_builder 297 + end 298 + end 299 + end
+97
lib/sinatra_more/markup_plugin/format_helpers.rb
··· 1 + # 2 + # sinatra_more 3 + # Copyright (c) 2009 Nathan Esquenazi 4 + # 5 + # Permission is hereby granted, free of charge, to any person obtaining 6 + # a copy of this software and associated documentation files (the 7 + # "Software"), to deal in the Software without restriction, including 8 + # without limitation the rights to use, copy, modify, merge, publish, 9 + # distribute, sublicense, and/or sell copies of the Software, and to 10 + # permit persons to whom the Software is furnished to do so, subject to 11 + # the following conditions: 12 + # 13 + # The above copyright notice and this permission notice shall be 14 + # included in all copies or substantial portions of the Software. 15 + # 16 + # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 + # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 + # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 + # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 + # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 + # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 + # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 + # 24 + 25 + module SinatraMore 26 + module FormatHelpers 27 + 28 + # Returns escaped text to protect against malicious content 29 + def escape_html(text) 30 + Rack::Utils.escape_html(text) 31 + end 32 + alias h escape_html 33 + alias sanitize_html escape_html 34 + 35 + # Returns escaped text to protect against malicious content 36 + # Returns blank if the text is empty 37 + def h!(text, blank_text = '&nbsp;') 38 + return blank_text if text.nil? || text.empty? 39 + h text 40 + end 41 + 42 + 43 + # Smart time helper which returns relative text representing times for recent dates 44 + # and absolutes for dates that are far removed from the current date 45 + # time_in_words(10.days.ago) => '10 days ago' 46 + def time_in_words(date) 47 + date = date.to_date 48 + date = Date.parse(date, true) unless /Date.*/ =~ date.class.to_s 49 + days = (date - Date.today).to_i 50 + 51 + return 'today' if days >= 0 and days < 1 52 + return 'tomorrow' if days >= 1 and days < 2 53 + return 'yesterday' if days >= -1 and days < 0 54 + 55 + return "in #{days} days" if days.abs < 60 and days > 0 56 + return "#{days.abs} days ago" if days.abs < 60 and days < 0 57 + 58 + return date.strftime('%A, %B %e') if days.abs < 182 59 + return date.strftime('%A, %B %e, %Y') 60 + end 61 + alias time_ago time_in_words 62 + 63 + # Returns relative time in words referencing the given date 64 + # relative_time_ago(Time.now) => 'about a minute ago' 65 + def relative_time_ago(from_time) 66 + distance_in_minutes = (((Time.now - from_time.to_time).abs)/60).round 67 + case distance_in_minutes 68 + when 0..1 then 'about a minute' 69 + when 2..44 then "#{distance_in_minutes} minutes" 70 + when 45..89 then 'about 1 hour' 71 + when 90..1439 then "about #{(distance_in_minutes.to_f / 60.0).round} hours" 72 + when 1440..2439 then '1 day' 73 + when 2440..2879 then 'about 2 days' 74 + when 2880..43199 then "#{(distance_in_minutes / 1440).round} days" 75 + when 43200..86399 then 'about 1 month' 76 + when 86400..525599 then "#{(distance_in_minutes / 43200).round} months" 77 + when 525600..1051199 then 'about 1 year' 78 + else "over #{(distance_in_minutes / 525600).round} years" 79 + end 80 + end 81 + 82 + # Used in xxxx.js.erb files to escape html so that it can be passed to javascript from sinatra 83 + # escape_javascript("<h1>Hey</h1>") 84 + def escape_javascript(html_content) 85 + return '' unless html_content 86 + javascript_mapping = { '\\' => '\\\\', '</' => '<\/', "\r\n" => '\n', "\n" => '\n' } 87 + javascript_mapping.merge("\r" => '\n', '"' => '\\"', "'" => "\\'") 88 + escaped_string = html_content.gsub(/(\\|<\/|\r\n|[\n\r"'])/) { javascript_mapping[$1] } 89 + "\"#{escaped_string}\"" 90 + end 91 + 92 + alias js_escape escape_javascript 93 + alias js_escape_html escape_javascript 94 + alias escape_for_javascript escape_javascript 95 + 96 + end 97 + end
+122
lib/sinatra_more/markup_plugin/output_helpers.rb
··· 1 + # 2 + # sinatra_more 3 + # Copyright (c) 2009 Nathan Esquenazi 4 + # 5 + # Permission is hereby granted, free of charge, to any person obtaining 6 + # a copy of this software and associated documentation files (the 7 + # "Software"), to deal in the Software without restriction, including 8 + # without limitation the rights to use, copy, modify, merge, publish, 9 + # distribute, sublicense, and/or sell copies of the Software, and to 10 + # permit persons to whom the Software is furnished to do so, subject to 11 + # the following conditions: 12 + # 13 + # The above copyright notice and this permission notice shall be 14 + # included in all copies or substantial portions of the Software. 15 + # 16 + # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 + # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 + # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 + # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 + # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 + # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 + # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 + # 24 + 25 + module SinatraMore 26 + module OutputHelpers 27 + # Captures the html from a block of template code for erb or haml 28 + # capture_html(&block) => "...html..." 29 + def capture_html(*args, &block) 30 + if self.respond_to?(:is_haml?) && is_haml? 31 + block_is_haml?(block) ? capture_haml(*args, &block) : block.call 32 + elsif has_erb_buffer? 33 + result_text = capture_erb(*args, &block) 34 + result_text.present? ? result_text : (block_given? && block.call(*args)) 35 + else # theres no template to capture, invoke the block directly 36 + block.call(*args) 37 + end 38 + end 39 + 40 + # Outputs the given text to the templates buffer directly 41 + # concat_content("This will be output to the template buffer in erb or haml") 42 + def concat_content(text="") 43 + if self.respond_to?(:is_haml?) && is_haml? 44 + haml_concat(text) 45 + elsif has_erb_buffer? 46 + erb_concat(text) 47 + else # theres no template to concat, return the text directly 48 + text 49 + end 50 + end 51 + 52 + # Returns true if the block is from an ERB or HAML template; false otherwise. 53 + # Used to determine if html should be returned or concatted to view 54 + # block_is_template?(block) 55 + def block_is_template?(block) 56 + block && (block_is_erb?(block) || (self.respond_to?(:block_is_haml?) && block_is_haml?(block))) 57 + end 58 + 59 + # Capture a block of content to be rendered at a later time. 60 + # Your blocks can also receive values, which are passed to them by <tt>yield_content</tt> 61 + # content_for(:name) { ...content... } 62 + # content_for(:name) { |name| ...content... } 63 + def content_for(key, &block) 64 + content_blocks[key.to_sym] << block 65 + end 66 + 67 + # Render the captured content blocks for a given key. 68 + # You can also pass values to the content blocks by passing them 69 + # as arguments after the key. 70 + # yield_content :include 71 + # yield_content :head, "param1", "param2" 72 + def yield_content(key, *args) 73 + blocks = content_blocks[key.to_sym] 74 + return nil if blocks.empty? 75 + blocks.map { |content| 76 + capture_html(*args, &content) 77 + }.join 78 + end 79 + 80 + protected 81 + 82 + # Retrieves content_blocks stored by content_for or within yield_content 83 + # content_blocks[:name] => ['...', '...'] 84 + def content_blocks 85 + @content_blocks ||= Hash.new {|h,k| h[k] = [] } 86 + end 87 + 88 + # Used to capture the html from a block of erb code 89 + # capture_erb(&block) => '...html...' 90 + def capture_erb(*args, &block) 91 + erb_with_output_buffer { block_given? && block.call(*args) } 92 + end 93 + 94 + # Concats directly to an erb template 95 + # erb_concat("Direct to buffer") 96 + def erb_concat(text) 97 + @_out_buf << text if has_erb_buffer? 98 + end 99 + 100 + # Returns true if an erb buffer is detected 101 + # has_erb_buffer? => true 102 + def has_erb_buffer? 103 + !@_out_buf.nil? 104 + end 105 + 106 + # Used to determine if a block is called from ERB. 107 + # NOTE: This doesn't actually work yet because the variable __in_erb_template 108 + # hasn't been defined in ERB. We need to find a way to fix this. 109 + def block_is_erb?(block) 110 + has_erb_buffer? || block && eval('defined? __in_erb_template', block) 111 + end 112 + 113 + # Used to direct the buffer for the erb capture 114 + def erb_with_output_buffer(buf = '') #:nodoc: 115 + @_out_buf, old_buffer = buf, @_out_buf 116 + yield 117 + @_out_buf 118 + ensure 119 + @_out_buf = old_buffer 120 + end 121 + end 122 + end
+78
lib/sinatra_more/markup_plugin/tag_helpers.rb
··· 1 + # 2 + # sinatra_more 3 + # Copyright (c) 2009 Nathan Esquenazi 4 + # 5 + # Permission is hereby granted, free of charge, to any person obtaining 6 + # a copy of this software and associated documentation files (the 7 + # "Software"), to deal in the Software without restriction, including 8 + # without limitation the rights to use, copy, modify, merge, publish, 9 + # distribute, sublicense, and/or sell copies of the Software, and to 10 + # permit persons to whom the Software is furnished to do so, subject to 11 + # the following conditions: 12 + # 13 + # The above copyright notice and this permission notice shall be 14 + # included in all copies or substantial portions of the Software. 15 + # 16 + # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 + # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 + # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 + # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 + # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 + # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 + # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 + # 24 + 25 + module SinatraMore 26 + module TagHelpers 27 + # Creates an html input field with given type and options 28 + # input_tag :text, :class => "test" 29 + def input_tag(type, options = {}) 30 + options.reverse_merge!(:type => type) 31 + tag(:input, options) 32 + end 33 + 34 + # Creates an html tag with given name, content and options 35 + # content_tag(:p, "hello", :class => 'light') 36 + # content_tag(:p, :class => 'dark') do ... end 37 + # parameters: content_tag(name, content=nil, options={}, &block) 38 + def content_tag(*args, &block) 39 + name = args.first 40 + options = args.extract_options! 41 + tag_html = block_given? ? capture_html(&block) : args[1] 42 + tag_result = tag(name, options.merge(:content => tag_html)) 43 + block_is_template?(block) ? concat_content(tag_result) : tag_result 44 + end 45 + 46 + # Creates an html tag with the given name and options 47 + # tag(:br, :style => 'clear:both') 48 + # tag(:p, :content => "hello", :class => 'large') 49 + def tag(name, options={}) 50 + content = options.delete(:content) 51 + identity_tag_attributes.each { |attr| options[attr] = attr.to_s if options[attr] } 52 + html_attrs = options.collect { |a, v| v.blank? ? nil : "#{a}=\"#{v}\"" }.compact.join(" ") 53 + base_tag = (!html_attrs.blank? ? "<#{name} #{html_attrs}" : "<#{name}") 54 + base_tag << (content ? ">#{content}</#{name}>" : " />") 55 + end 56 + 57 + def meta_tag(name, content, options = {}) 58 + html_attrs = options.collect{|a,v| 59 + if v.blank? 60 + nil 61 + else 62 + "#{Rack::Utils.escape_html(a)}=\"#{Rack::Utils.escape_html(v)}\"" 63 + end 64 + }.compact.join(" ") 65 + 66 + "<meta name=\"#{Rack::Utils.escape_html(name)}\" " << 67 + "content=\"#{Rack::Utils.escape_html(content)}\" " << 68 + (html_attrs.blank? ? "" : html_attrs << " ") << "/>" 69 + end 70 + 71 + protected 72 + 73 + # Returns a list of attributes which can only contain an identity value (i.e selected) 74 + def identity_tag_attributes 75 + [:checked, :disabled, :selected, :multiple] 76 + end 77 + end 78 + end
+34
lib/sinatra_more/render_plugin.rb
··· 1 + # 2 + # sinatra_more 3 + # Copyright (c) 2009 Nathan Esquenazi 4 + # 5 + # Permission is hereby granted, free of charge, to any person obtaining 6 + # a copy of this software and associated documentation files (the 7 + # "Software"), to deal in the Software without restriction, including 8 + # without limitation the rights to use, copy, modify, merge, publish, 9 + # distribute, sublicense, and/or sell copies of the Software, and to 10 + # permit persons to whom the Software is furnished to do so, subject to 11 + # the following conditions: 12 + # 13 + # The above copyright notice and this permission notice shall be 14 + # included in all copies or substantial portions of the Software. 15 + # 16 + # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 + # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 + # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 + # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 + # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 + # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 + # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 + # 24 + 25 + require File.dirname(__FILE__) + '/support_lite' 26 + Dir[File.dirname(__FILE__) + '/render_plugin/**/*.rb'].each {|file| load file } 27 + 28 + module SinatraMore 29 + module RenderPlugin 30 + def self.registered(app) 31 + app.helpers RenderHelpers 32 + end 33 + end 34 + end
+85
lib/sinatra_more/render_plugin/render_helpers.rb
··· 1 + # 2 + # sinatra_more 3 + # Copyright (c) 2009 Nathan Esquenazi 4 + # 5 + # Permission is hereby granted, free of charge, to any person obtaining 6 + # a copy of this software and associated documentation files (the 7 + # "Software"), to deal in the Software without restriction, including 8 + # without limitation the rights to use, copy, modify, merge, publish, 9 + # distribute, sublicense, and/or sell copies of the Software, and to 10 + # permit persons to whom the Software is furnished to do so, subject to 11 + # the following conditions: 12 + # 13 + # The above copyright notice and this permission notice shall be 14 + # included in all copies or substantial portions of the Software. 15 + # 16 + # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 + # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 + # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 + # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 + # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 + # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 + # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 + # 24 + 25 + module SinatraMore 26 + module RenderHelpers 27 + # Renders a erb template based on the relative path 28 + # erb_template 'users/new' 29 + def erb_template(template_path, options={}) 30 + render_template template_path, options.merge(:template_engine => :erb) 31 + end 32 + 33 + # Renders a haml template based on the relative path 34 + # haml_template 'users/new' 35 + def haml_template(template_path, options={}) 36 + render_template template_path, options.merge(:template_engine => :haml) 37 + end 38 + 39 + # Renders a template from a file path automatically determining rendering engine 40 + # render_template 'users/new' 41 + # options = { :template_engine => 'haml' } 42 + def render_template(template_path, options={}) 43 + template_engine = options.delete(:template_engine) || resolve_template_engine(template_path) 44 + render template_engine.to_sym, template_path.to_sym, options 45 + end 46 + 47 + # Partials implementation which includes collections support 48 + # partial 'photo/_item', :object => @photo 49 + # partial 'photo/_item', :collection => @photos 50 + def partial(template, options={}) 51 + options.reverse_merge!(:locals => {}, :layout => false) 52 + path = template.to_s.split(File::SEPARATOR) 53 + object_name = path[-1].to_sym 54 + path[-1] = "_#{path[-1]}" 55 + template_path = File.join(path) 56 + raise 'Partial collection specified but is nil' if options.has_key?(:collection) && options[:collection].nil? 57 + if collection = options.delete(:collection) 58 + options.delete(:object) 59 + counter = 0 60 + collection.collect do |member| 61 + counter += 1 62 + options[:locals].merge!(object_name => member, "#{object_name}_counter".to_sym => counter) 63 + render_template(template_path, options.merge(:layout => false)) 64 + end.join("\n") 65 + else 66 + if member = options.delete(:object) 67 + options[:locals].merge!(object_name => member) 68 + end 69 + render_template(template_path, options.merge(:layout => false)) 70 + end 71 + end 72 + alias render_partial partial 73 + 74 + private 75 + 76 + # Returns the template engine (i.e haml) to use for a given template_path 77 + # resolve_template_engine('users/new') => :haml 78 + def resolve_template_engine(template_path) 79 + resolved_template_path = File.join(self.settings.views, template_path.to_s + ".*") 80 + template_file = Dir[resolved_template_path].first 81 + raise "Template path '#{template_path}' could not be located in views!" unless template_file 82 + template_engine = File.extname(template_file)[1..-1].to_sym 83 + end 84 + end 85 + end
+45
lib/sinatra_more/support_lite.rb
··· 1 + # 2 + # sinatra_more 3 + # Copyright (c) 2009 Nathan Esquenazi 4 + # 5 + # Permission is hereby granted, free of charge, to any person obtaining 6 + # a copy of this software and associated documentation files (the 7 + # "Software"), to deal in the Software without restriction, including 8 + # without limitation the rights to use, copy, modify, merge, publish, 9 + # distribute, sublicense, and/or sell copies of the Software, and to 10 + # permit persons to whom the Software is furnished to do so, subject to 11 + # the following conditions: 12 + # 13 + # The above copyright notice and this permission notice shall be 14 + # included in all copies or substantial portions of the Software. 15 + # 16 + # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 + # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 + # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 + # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 + # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 + # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 + # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 + # 24 + 25 + # This is for adding specific methods that are required by sinatra_more if activesupport isn't required 26 + 27 + require 'yaml' unless defined?(YAML) 28 + 29 + unless String.method_defined?(:titleize) && Hash.method_defined?(:slice) 30 + require 'active_support/core_ext/kernel' 31 + require 'active_support/core_ext/array' 32 + require 'active_support/core_ext/hash' 33 + require 'active_support/core_ext/module' 34 + require 'active_support/core_ext/class' 35 + require 'active_support/deprecation' 36 + require 'active_support/inflector' 37 + end 38 + 39 + unless String.method_defined?(:blank?) 40 + begin 41 + require 'active_support/core_ext/object/blank' 42 + rescue LoadError 43 + require 'active_support/core_ext/blank' 44 + end 45 + end