sinatra-support 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,78 @@
1
+ # Useful HTML helpers.
2
+ #
3
+ # require 'sinatra/support/htmlhelpers'
4
+ #
5
+ # class Main < Sinatra::Base
6
+ # helpers Sinatra::HtmlHelpers
7
+ # end
8
+ #
9
+ # == Helpers
10
+ #
11
+ # This provides the following helpers:
12
+ #
13
+ # === {#h h} - Escapes HTML output
14
+ # <a href="<%= h url %>">
15
+ #
16
+ # === {#tag tag} - Builds HTML tags
17
+ # tag :a #=> "<a>"
18
+ # tag :strong, "Yes" #=> "<strong>Yes</strong>"
19
+ # tag :a, "OK", href: "#" #=> "<a href='#'>OK</a>"
20
+ #
21
+ module Sinatra::HtmlHelpers
22
+ # Returns an HTML sanitized string.
23
+ def h(str)
24
+ Rack::Utils.escape_html(str)
25
+ end
26
+
27
+ # Accepts a list of pairs and produces option tags.
28
+ #
29
+ # @example
30
+ #
31
+ # select_options([['One', 1], ['Two', 2]])
32
+ # select_options([['One', 1], ['Two', 2]], 1)
33
+ # select_options([['One', 1], ['Two', 2]], 1, '- Choose -')
34
+ #
35
+ # # using it with the provided date helpers...
36
+ # select_options year_choices, 2010 # select 2010 as default
37
+ # select_options month_choices, 5 # select May as default
38
+ # select_options day_choices, 25 # select the 25th as default
39
+ #
40
+ # @param [Array] pairs a collection of label, value tuples.
41
+ # @param [Object] current the current value of this select.
42
+ # @param [#to_s] prompt a default prompt to place at the beginning
43
+ # of the list.
44
+ def select_options(pairs, current = nil, prompt = nil)
45
+ pairs.unshift([prompt, '']) if prompt
46
+
47
+ pairs.map { |label, value|
48
+ tag(:option, label, :value => value, :selected => (current == value))
49
+ }.join("\n")
50
+ end
51
+
52
+ # Builds a tag.
53
+ def tag(tag, content, atts = {})
54
+ if self_closing?(tag)
55
+ %(<#{ tag }#{ tag_attributes(atts) } />)
56
+ else
57
+ %(<#{ tag }#{ tag_attributes(atts) }>#{h content}</#{ tag }>)
58
+ end
59
+ end
60
+
61
+ def tag_attributes(atts = {})
62
+ atts.inject([]) { |a, (k, v)|
63
+ a << (' %s="%s"' % [k, escape_attr(v)]) if v
64
+ a
65
+ }.join('')
66
+ end
67
+
68
+ def escape_attr(str)
69
+ str.to_s.gsub("'", "&#39;").gsub('"', "&quot;")
70
+ end
71
+
72
+ def self_closing?(tag)
73
+ @self_closing ||= [:area, :base, :basefont, :br, :hr,
74
+ :input, :img, :link, :meta]
75
+
76
+ @self_closing.include?(tag.to_sym)
77
+ end
78
+ end
@@ -0,0 +1,118 @@
1
+ # I18n support.
2
+ #
3
+ # require 'sinatra/support/i18nsupport'
4
+ #
5
+ # class Main < Sinatra::Base
6
+ # register Sinatra::I18nSupport
7
+ # load_locales './config/locales'
8
+ # set :default_locale, 'fr' # Optional; defaults to 'en'
9
+ # end
10
+ #
11
+ # Be sure that you have the +I18n+ gem.
12
+ #
13
+ # # Gemfile
14
+ # gem "i18n"
15
+ #
16
+ # (or +gem install i18n+)
17
+ #
18
+ # Then put your locale YAML files into +./config/locales+ (whatever path you
19
+ # use for {#load_locales}:
20
+ #
21
+ # # config/locales/en.yml
22
+ # en:
23
+ # an_article: "An article"
24
+ #
25
+ # == Helpers
26
+ #
27
+ # === {Helpers#t t} - Translates something.
28
+ #
29
+ # <h3><%= t('article.an_article') %></h3>
30
+ # <h5><%= t('article.delete', name: @article.to_s) %></h5>
31
+ #
32
+ # === {Helpers#t l} - Localizes something.
33
+ #
34
+ # <%= l(Time.now) %>
35
+ # <%= l(Time.now, format: :short) %>
36
+ #
37
+ # === {Helpers#current_locale current_locale} - Returns the current locale name.
38
+ #
39
+ # <script>
40
+ # window.locale = <%= current_locale.inspect %>;
41
+ # </script>
42
+ #
43
+ # === {Helpers#available_locales available_locales} - A list of available locales.
44
+ #
45
+ # <% if available_locales.include?(:es) %>
46
+ # <a href="/locales/es">en Espanol</a>
47
+ # <% end %>
48
+ #
49
+ # == Changing locales
50
+ #
51
+ # Set +session[:locale]+ to the locale name.
52
+ #
53
+ # get '/locales/:locale' do |locale|
54
+ # not_found unless locales.include?(locale)
55
+ # session[:locale] = locale
56
+ # end
57
+ #
58
+ # If you want to override the way of checking for the current locale,
59
+ # simply redefine the `current_locale` helper:
60
+ #
61
+ # helpers do
62
+ # def current_locale
63
+ # current_user.locale || session[:locale] || settings.default_locale
64
+ # end
65
+ # end
66
+ #
67
+ # == Locale files
68
+ #
69
+ # This gem does not ship with default options for time, date and such.
70
+ # You may want to get those from:
71
+ #
72
+ # https://github.com/svenfuchs/rails-i18n/tree/master/rails/locale
73
+ #
74
+ # == Using a different backend
75
+ #
76
+ # Instead of calling {#load_locales}, just load the right I18n backend
77
+ # using the I18n gem.
78
+ #
79
+ # You can also just use I18n.store_translations if you still want to use
80
+ # the default simple I18n backend.
81
+ #
82
+ # == Settings
83
+ #
84
+ # [+default_locale+] The locale to use by default. Defaults to +"en"+.
85
+ #
86
+ module Sinatra::I18nSupport
87
+ def self.registered(app)
88
+ require 'i18n'
89
+ app.set :default_locale, 'en'
90
+ app.helpers Helpers
91
+ end
92
+
93
+ # Loads the locales in the given path.
94
+ def load_locales(path)
95
+ Dir[File.join(path, '*.yml')].each do |file|
96
+ I18n.backend.load_translations file
97
+ end
98
+ end
99
+
100
+ module Helpers
101
+ # Override this if you need to, say, check for the user's preferred locale.
102
+ def current_locale
103
+ session[:locale] || settings.default_locale
104
+ end
105
+
106
+ def available_locales
107
+ I18n.available_locales
108
+ end
109
+
110
+ def l(what, options={})
111
+ I18n.l what, {:locale => current_locale}.merge(options)
112
+ end
113
+
114
+ def t(what, options={})
115
+ I18n.t what, {:locale => current_locale}.merge(options)
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,63 @@
1
+ # Useful HAML condition helpers.
2
+ #
3
+ # require 'sinatra/support/htmlhelpers'
4
+ #
5
+ # class Main < Sinatra::Base
6
+ # helpers Sinatra::IfHelpers
7
+ # end
8
+ #
9
+ # == Helpers
10
+ #
11
+ # These are helpers you can use in HAML files.
12
+ #
13
+ # === {#active_if active_if} - Adds +class=active+ if a condition passes.
14
+ #
15
+ # - @users.each do |user|
16
+ # %li{active_if(user == current_user)}
17
+ # = user.to_s
18
+ #
19
+ # === {#checked_if checked_if} - Adds +checked=1+.
20
+ #
21
+ # %input{checked_if(page.available?), type: 'checkbox'}
22
+ #
23
+ # === {#hide_if hide_if} - Adds +style=display:none+.
24
+ #
25
+ # %div#comments{hide_if(post.comments.empty?)}
26
+ #
27
+ # === {#show_if show_if} - Inverse of +hide_if+.
28
+ #
29
+ # === {#selected_if selected_if} - Adds +selected=1+.
30
+ #
31
+ # === {#disabled_if disabled_if} - Adds +disabled=1+.
32
+ #
33
+ # === {#enabled_if enabled_if} - Inverse of +disabled_if+.
34
+ #
35
+ module Sinatra::IfHelpers
36
+ def active_if(condition)
37
+ condition ? {:class => 'active'} : {}
38
+ end
39
+
40
+ def checked_if(condition)
41
+ condition ? {:checked => '1'} : {}
42
+ end
43
+
44
+ def selected_if(condition)
45
+ condition ? {:selected => '1'} : {}
46
+ end
47
+
48
+ def disabled_if(condition)
49
+ condition ? {:disabled => '1'} : {}
50
+ end
51
+
52
+ def enabled_if(condition)
53
+ disabled_if !condition
54
+ end
55
+
56
+ def hide_if(condition)
57
+ condition ? {:style => 'display:none'} : {}
58
+ end
59
+
60
+ def show_if(condition)
61
+ hide_if !condition
62
+ end
63
+ end
@@ -0,0 +1,50 @@
1
+ # Adds a route for JavaScript files.
2
+ #
3
+ # == Usage
4
+ #
5
+ # require 'sinatra/support/jssupport'
6
+ #
7
+ # Use {#serve_js} in the Sinatra DSL to serve up files.
8
+ #
9
+ # register Sinatra::JsSupport
10
+ # serve_js '/js', from: './app/js'
11
+ #
12
+ # Assuming you have a +app/js/jquery.js+ file, you will
13
+ # then be able to access it from the given URL prefix.
14
+ #
15
+ # $ curl "http://localhost:4567/js/jquery.js"
16
+ #
17
+ # This plugin supports CoffeeScript. To use it, simply
18
+ # add a CoffeeScript file in the JS file path.
19
+ #
20
+ # # Will first try app/js/application.coffee,
21
+ # # then move onto app/js/application.js if it's not found.
22
+ #
23
+ # $ curl "http://localhost:4567/js/application.js"
24
+ #
25
+ # To use CoffeeScript, you will need the +coffee_script+ gem.
26
+ #
27
+ module Sinatra::JsSupport
28
+ def self.registered(app)
29
+ app.set :js_max_age, app.development? ? 0 : 86400*30
30
+ end
31
+
32
+ def serve_js(url_prefix, options={})
33
+ path = File.join(url_prefix, '*.js')
34
+ prefix = options[:from]
35
+
36
+ get path do |name|
37
+ fname = Dir[File.join(prefix, "#{name}.{js,coffee}")].first or pass
38
+
39
+ content_type :js
40
+ last_modified File.mtime(fname)
41
+ cache_control :public, :must_revalidate, :max_age => settings.js_max_age
42
+
43
+ if fname =~ /\.coffee$/
44
+ coffee File.read(fname)
45
+ else
46
+ send_file fname
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,105 @@
1
+ # Provides numeric helpers.
2
+ #
3
+ # require 'sinatra/support/numeric'
4
+ #
5
+ # class Main < Sinatra::Base
6
+ # register Sinatra::Numeric
7
+ # end
8
+ #
9
+ # == Helpers
10
+ #
11
+ # This plugin provides the following helpers:
12
+ #
13
+ # === {Helpers#currency currency} - Formats a string as a currency.
14
+ #
15
+ # <%= currency(100) %>
16
+ # <!-- $100 -->
17
+ #
18
+ # == {Helpers#percentage percentage} - Formats a number as a percentage.
19
+ #
20
+ # <%= percentage(100) %>
21
+ # <!-- 100.00% -->
22
+ #
23
+ # == Settings
24
+ #
25
+ # You may change the settings like so:
26
+ #
27
+ # Main.configure do |m|
28
+ # m.set :default_currency_unit, '$'
29
+ # m.set :default_currency_precision, 2
30
+ # m.set :default_currency_separator, ','
31
+ # end
32
+ #
33
+ module Sinatra::Numeric
34
+ def self.registered(app)
35
+ app.set :default_currency_unit, '$'
36
+ app.set :default_currency_precision, 2
37
+ app.set :default_currency_separator, ','
38
+
39
+ app.helpers Helpers
40
+ end
41
+
42
+ module Helpers
43
+ # Formats a number into a currency display. Uses the following settings:
44
+ #
45
+ # - settings.default_currency_unit (defaults to '$')
46
+ # - settings.default_currency_precision (defaults to 2)
47
+ # - settings.default_currenty_separator (defaults to ',')
48
+ #
49
+ # @example
50
+ #
51
+ # currency(100) == "$ 100.00"
52
+ # # => true
53
+ #
54
+ # currency(100, :unit => "&pound;") == "&pound; 100.00"
55
+ # # => true
56
+ #
57
+ # currency(100, :precision => 0) == "$ 100"
58
+ # => # true
59
+ #
60
+ # # somewhere in your sinatra context after registering Sinatra::Support
61
+ # set :default_currency_unit, '&pound;'
62
+ # set :default_currency_precision, 3
63
+ # set :default_currency_separator, ' '
64
+ #
65
+ # currency(100) == "&pound; 100.000"
66
+ # # => true
67
+ #
68
+ # @param [Numeric] number the number you wish to display as a currency.
69
+ # @param [Hash] opts the various options available.
70
+ # @option opts [#to_s] :unit (defaults to '$')
71
+ # @option opts [Fixnum] :precision (defaults to 2)
72
+ # @option opts [#to_s] :separator (defaults to ',')
73
+ # @return [String] the formatted string based on `number`.
74
+ # @return [nil] if given nil or an empty string.
75
+ def currency(number, opts = {})
76
+ return if number.to_s.empty?
77
+
78
+ unit = opts[:unit] || settings.default_currency_unit
79
+ precision = opts[:precision] || settings.default_currency_precision
80
+ separator = opts[:separator] || settings.default_currency_separator
81
+
82
+ ret = "%s %.#{ Integer(precision) }f" % [unit, number]
83
+ parts = ret.split('.')
84
+ parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{separator}")
85
+ parts.join('.')
86
+ end
87
+
88
+ # Show the percentage representation of a numeric value.
89
+ #
90
+ # @example
91
+ # percentage(100) == "100.00%"
92
+ # percentage(100, 0) == "100%"
93
+ #
94
+ # @param [Numeric] number A numeric value
95
+ # @param [Fixnum] precision (defaults to 2) Number of decimals to show.
96
+ # @return [String] the number displayed as a percentage
97
+ # @return [nil] given a nil value or an empty string.
98
+ def percentage(number, precision = 2)
99
+ return if number.to_s.empty?
100
+
101
+ ret = "%02.#{ precision }f%" % number
102
+ ret.gsub(/\.0*%$/, '%')
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,75 @@
1
+ # Ohm error helpers.
2
+ #
3
+ # # Only for those who use Ohm and HAML.
4
+ # require 'ohm'
5
+ # require 'haml'
6
+ #
7
+ # require 'sinatra/support/ohmerrorhelpers'
8
+ #
9
+ # class Main < Sinatra::Base
10
+ # helpers Sinatra::OhmErrorHelpers
11
+ # end
12
+ #
13
+ # == Common usage
14
+ #
15
+ # - errors_on @user do |e|
16
+ # - e.on [:email, :not_present], "We need your email address."
17
+ # - e.on [:password, :not_present], "You must specify a password."
18
+ #
19
+ # This produces the following:
20
+ #
21
+ # <div class="errors">
22
+ # <ul>
23
+ # <li>We need your email address</li>
24
+ # <li>You must specify a password.</li>
25
+ # </ul>
26
+ # </div>
27
+ #
28
+ module Sinatra::OhmErrorHelpers
29
+ # Presents errors on your form. Takes the explicit approach and assumes
30
+ # that for every form you have, the copy for the errors are important,
31
+ # instead of producing canned responses.
32
+ #
33
+ # @param [#errors] object An object responding to #errors. This validation
34
+ # also checks for the presence of a #full_messages method
35
+ # in the errors object for compatibility with
36
+ # ActiveRecord style objects.
37
+ # @param [Hash] options a hash of HTML attributes to place on the
38
+ # containing div.
39
+ # @option options [#to_s] :class (defaults to errors) The css class to put
40
+ # in the div.
41
+ #
42
+ # @yield [Sinatra::Support::HamlErrorPresenter] an object responding to #on.
43
+ #
44
+ def errors_on(object, options = { :class => 'errors' }, &block)
45
+ return if object.errors.empty?
46
+
47
+ lines = if object.errors.respond_to?(:full_messages)
48
+ object.errors.full_messages
49
+ else
50
+ HamlErrorPresenter.new(object.errors).present(self, &block)
51
+ end
52
+
53
+ haml_tag(:div, options) do
54
+ haml_tag(:ul) do
55
+ lines.each do |error|
56
+ haml_tag(:li, error)
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ # @see http://github.com/citrusbyte/reddit-clone
63
+ class HamlErrorPresenter < Ohm::Validations::Presenter
64
+ def on(error, message = (block_given? ? @context.capture_haml { yield } : raise(ArgumentError)))
65
+ handle(error) do
66
+ @output << message
67
+ end
68
+ end
69
+
70
+ def present(context)
71
+ @context = context
72
+ super()
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,9 @@
1
+ module Sinatra
2
+ module Support
3
+ VERSION = "1.0.1"
4
+
5
+ def self.version
6
+ VERSION
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,17 @@
1
+ require File.expand_path('../support/version', __FILE__)
2
+
3
+ module Sinatra
4
+ autoload :Country, File.expand_path('../support/country', __FILE__)
5
+ autoload :CountryHelpers, File.expand_path('../support/countryhelpers', __FILE__)
6
+ autoload :CssSupport, File.expand_path('../support/csssupport', __FILE__)
7
+ autoload :DateForms, File.expand_path('../support/dateforms', __FILE__)
8
+ autoload :HtmlHelpers, File.expand_path('../support/htmlhelpers', __FILE__)
9
+ autoload :JsSupport, File.expand_path('../support/jssupport', __FILE__)
10
+ autoload :OhmErrorHelpers, File.expand_path('../support/ohmerrorhelpers', __FILE__)
11
+ autoload :Numeric, File.expand_path('../support/numeric', __FILE__)
12
+ autoload :IfHelpers, File.expand_path('../support/ifhelpers', __FILE__)
13
+ autoload :I18nSupport, File.expand_path('../support/i18nsupport', __FILE__)
14
+
15
+ module Support
16
+ end
17
+ end
@@ -0,0 +1,15 @@
1
+ en:
2
+ article:
3
+ new: "New Article"
4
+
5
+ time:
6
+ formats:
7
+ default: %a, %d. %b %Y %H:%M:%S %z
8
+ short: %d. %b %H:%M
9
+ am: "am"
10
+ pm: "pm"
11
+
12
+ date:
13
+ abbr_day_names: [Sun, Mon, Tue, Wed, Thu, Fri, Sat]
14
+ abbr_month_names: [~, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec]
15
+
@@ -0,0 +1,15 @@
1
+ tl:
2
+ article:
3
+ new: "Bagong Artikulo"
4
+
5
+ time:
6
+ formats:
7
+ default: %a, %d. %b %Y %H:%M:%S %z
8
+ short: %d. %b %H:%M
9
+ am: "am"
10
+ pm: "pm"
11
+
12
+ date:
13
+ abbr_day_names: [Sun, Mon, Tue, Wed, Thu, Fri, Sat]
14
+ abbr_month_names: [~, Ene, Peb, Mar, Abr, May, Hun, Hul, Aug, Set, Okt, Nob, Des]
15
+
data/test/helper.rb ADDED
@@ -0,0 +1,29 @@
1
+ require 'rubygems' unless RUBY_VERSION >= '1.9'
2
+ require 'test/unit'
3
+ require 'contest'
4
+ require 'ohm'
5
+ require 'haml'
6
+ require 'mocha'
7
+ require 'rack/test'
8
+ require 'nokogiri'
9
+ require 'sinatra'
10
+
11
+ $:.unshift File.expand_path('../../lib', __FILE__)
12
+ $:.unshift File.dirname(__FILE__)
13
+
14
+ require 'sinatra/support'
15
+
16
+ class Test::Unit::TestCase
17
+ def settings
18
+ @app ||= Sinatra::Application.new
19
+ end
20
+
21
+ def self.fixture_path(*a)
22
+ root = File.expand_path('../fixtures', __FILE__)
23
+ File.join root, a
24
+ end
25
+
26
+ def fixture_path(*a)
27
+ self.class.fixture_path *a
28
+ end
29
+ end
@@ -0,0 +1,35 @@
1
+ require File.expand_path('../helper', __FILE__)
2
+
3
+ class CountryTest < Test::Unit::TestCase
4
+ include Sinatra::CountryHelpers
5
+
6
+ Country = Sinatra::Country
7
+
8
+ test "country_choices returns Country.to_select" do
9
+ assert_equal Country.to_select, country_choices
10
+ end
11
+
12
+ test "241 countries" do
13
+ assert_equal 246, Country.to_select.length
14
+ end
15
+
16
+ test "has a matching name for all keys" do
17
+ Country.all.each do |code, name|
18
+ assert_equal name, Country[code]
19
+ assert_equal name, Country[code.to_s]
20
+ end
21
+ end
22
+
23
+ test "random returns a valid code" do
24
+ 246.times {
25
+ assert Country[Country.random]
26
+ }
27
+ end
28
+
29
+ test "finding a country with wrong parameters" do
30
+ assert_nil Country[""]
31
+ assert_nil Country[nil]
32
+ assert_nil Country[:XX]
33
+ assert_nil Country["XX"]
34
+ end
35
+ end