sinatra-support 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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