sinatra-hat 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.markdown +27 -0
- data/Rakefile +58 -0
- data/VERSION +1 -0
- data/lib/gettext/haml.rb +36 -0
- data/lib/gettext/haml_parser.rb +64 -0
- data/lib/gettext/ruby19_fix.rb +20 -0
- data/lib/rack/fastcgi_fix.rb +14 -0
- data/lib/rack/gettext_reloader.rb +63 -0
- data/lib/sequel/utf8_fix.rb +15 -0
- data/lib/sinatra-hat.rb +153 -0
- data/lib/sinatra/reloader.rb +11 -0
- data/lib/sinatra/template_cache.rb +27 -0
- data/test/sinatra-hat_test.rb +6 -0
- data/test/test_helper.rb +9 -0
- metadata +82 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Adam Strzelecki
|
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.
|
data/README.markdown
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
Sinatra Hat
|
2
|
+
===========
|
3
|
+
This is a set of extensions for *Sinatra* and relative gems such as *Sequel*, *Haml*, *GetText*.
|
4
|
+
|
5
|
+
It adds following functions to your *Sinatra* project:
|
6
|
+
|
7
|
+
- Automatic translation using *GetText* or *Fast_Gettext* of *Haml* templates, and parser for `po` file generation
|
8
|
+
- Several fixes for *Sequel*, *Rack*
|
9
|
+
- Rack reloader for *Sinatra* and *GetText* translations
|
10
|
+
- String permalinks and date extensions
|
11
|
+
|
12
|
+
Setup
|
13
|
+
=====
|
14
|
+
### 1. Install
|
15
|
+
sudo gem install nanoant-sinatra-hat -s http://gems.github.com/
|
16
|
+
|
17
|
+
Or from source:
|
18
|
+
|
19
|
+
git clone git://github.com/nanoant/sinatra-hat.git
|
20
|
+
cd sinatra-hat && rake install
|
21
|
+
|
22
|
+
Author
|
23
|
+
======
|
24
|
+
[Adam Strzelecki](http://www.nanoant.com/)
|
25
|
+
ono@java.pl
|
26
|
+
|
27
|
+
Released under MIT license, see `MIT-LICENSE` for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "sinatra-hat"
|
8
|
+
gem.description = "Sinatra Ruby gem extensions for gettext, caching, reloading, etc."
|
9
|
+
gem.summary = "Sinatra Ruby gem extensions for gettext, caching, reloading, etc."
|
10
|
+
gem.email = "ono@java.pl"
|
11
|
+
gem.homepage = "http://github.com/nanoant/sinatra-hat"
|
12
|
+
gem.authors = ["Adam Strzelecki"]
|
13
|
+
gem.files = FileList['lib/**/*.rb', 'bin/*', '[A-Z]*', 'test/**/*'].to_a
|
14
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
15
|
+
end
|
16
|
+
|
17
|
+
rescue LoadError
|
18
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'rake/testtask'
|
22
|
+
Rake::TestTask.new(:test) do |test|
|
23
|
+
test.libs << 'lib' << 'test'
|
24
|
+
test.pattern = 'test/**/*_test.rb'
|
25
|
+
test.verbose = true
|
26
|
+
end
|
27
|
+
|
28
|
+
begin
|
29
|
+
require 'rcov/rcovtask'
|
30
|
+
Rcov::RcovTask.new do |test|
|
31
|
+
test.libs << 'test'
|
32
|
+
test.pattern = 'test/**/*_test.rb'
|
33
|
+
test.verbose = true
|
34
|
+
end
|
35
|
+
rescue LoadError
|
36
|
+
task :rcov do
|
37
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
task :default => :test
|
43
|
+
|
44
|
+
require 'rake/rdoctask'
|
45
|
+
Rake::RDocTask.new do |rdoc|
|
46
|
+
if File.exist?('VERSION.yml')
|
47
|
+
config = YAML.load(File.read('VERSION.yml'))
|
48
|
+
version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
|
49
|
+
else
|
50
|
+
version = ""
|
51
|
+
end
|
52
|
+
|
53
|
+
rdoc.rdoc_dir = 'rdoc'
|
54
|
+
rdoc.title = "sinatra-hat #{version}"
|
55
|
+
rdoc.rdoc_files.include('README*')
|
56
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
57
|
+
end
|
58
|
+
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.4
|
data/lib/gettext/haml.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# Haml gettext module providing gettext translation for all Haml plain text
|
2
|
+
# calls
|
3
|
+
# http://pastie.org/445295
|
4
|
+
|
5
|
+
class Haml::Engine
|
6
|
+
# Inject _ gettext into plain text and tag plain text calls
|
7
|
+
def push_plain(text, options = {})
|
8
|
+
super(_(text), options)
|
9
|
+
end
|
10
|
+
def parse_tag(line)
|
11
|
+
tag_name, attributes, attributes_hashes, object_ref, nuke_outer_whitespace,
|
12
|
+
nuke_inner_whitespace, action, value, last_line = super(line)
|
13
|
+
value = _(value) unless action && action != '!' || action == '!' && value[0..0] == '=' || value.empty?
|
14
|
+
# translate inline ruby code too
|
15
|
+
value.gsub!(/_\('([^']+)'\)/) {|m| '\''+_($1)+'\''} unless action != '=' || value.empty?
|
16
|
+
attributes_hashes.each{|h| h.each{|v| v.gsub!(/_\('([^']+)'\)/){|m| '\''+_($1)+'\''} if v.is_a? String} unless h.nil? || h.empty?} unless attributes_hashes.nil? || attributes_hashes.empty?
|
17
|
+
[tag_name, attributes, attributes_hashes, object_ref, nuke_outer_whitespace,
|
18
|
+
nuke_inner_whitespace, action, value, last_line]
|
19
|
+
end
|
20
|
+
def push_flat(line)
|
21
|
+
return super(line) if @gettext_filters.nil? || !@gettext_filters.last
|
22
|
+
text = line.full.dup
|
23
|
+
text = "" unless text.gsub!(/^#{@flat_spaces}/, '')
|
24
|
+
text = _(text) if text != ''
|
25
|
+
@filter_buffer << "#{text}\n"
|
26
|
+
end
|
27
|
+
def start_filtered(name)
|
28
|
+
@gettext_filters ||= []
|
29
|
+
@gettext_filters.push( (name == 'markdown') )
|
30
|
+
super
|
31
|
+
end
|
32
|
+
def close_filtered(filter)
|
33
|
+
@gettext_filters.pop
|
34
|
+
super
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# Haml gettext parser module
|
2
|
+
# http://pastie.org/445297
|
3
|
+
|
4
|
+
require 'gettext/tools/rgettext'
|
5
|
+
require 'gettext/tools/parser/ruby'
|
6
|
+
require 'haml'
|
7
|
+
|
8
|
+
class String
|
9
|
+
def escape_single_quotes
|
10
|
+
self.gsub(/'/, "\\\\'")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Haml::Engine
|
15
|
+
# Overriden function that parses Haml tags
|
16
|
+
# Injects gettext call for plain text action.
|
17
|
+
def parse_tag(line)
|
18
|
+
tag_name, attributes, attributes_hashes, object_ref, nuke_outer_whitespace,
|
19
|
+
nuke_inner_whitespace, action, value, last_line = super(line)
|
20
|
+
@precompiled << "_('#{value.escape_single_quotes}')\n" unless action && action != '!' || action == '!' && value[0..0] == '=' || value.empty?
|
21
|
+
[tag_name, attributes, attributes_hashes, object_ref, nuke_outer_whitespace,
|
22
|
+
nuke_inner_whitespace, action, value, last_line]
|
23
|
+
end
|
24
|
+
# Overriden function that producted Haml plain text
|
25
|
+
# Injects gettext call for plain text action.
|
26
|
+
def push_plain(text, options = {})
|
27
|
+
@precompiled << "_('#{text.escape_single_quotes}')\n"
|
28
|
+
end
|
29
|
+
def push_flat(line)
|
30
|
+
return super(line) if @gettext_filters.nil? || !@gettext_filters.last
|
31
|
+
text = line.unstripped
|
32
|
+
return if text == ''
|
33
|
+
@precompiled << "_('#{text.escape_single_quotes}')\n"
|
34
|
+
end
|
35
|
+
def start_filtered(name)
|
36
|
+
@gettext_filters ||= []
|
37
|
+
@gettext_filters.push( (name == 'markdown') )
|
38
|
+
super
|
39
|
+
end
|
40
|
+
def close_filtered(filter)
|
41
|
+
@gettext_filters.pop
|
42
|
+
super
|
43
|
+
end
|
44
|
+
def flush_merged_text
|
45
|
+
# We override this method, becuase code generated here confuses GetText's Ruby parser
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Haml gettext parser
|
50
|
+
module HamlParser
|
51
|
+
module_function
|
52
|
+
|
53
|
+
def target?(file)
|
54
|
+
File.extname(file) == ".haml"
|
55
|
+
end
|
56
|
+
|
57
|
+
def parse(file, ary = [])
|
58
|
+
haml = Haml::Engine.new(IO.readlines(file).join)
|
59
|
+
code = haml.precompiled.split(/$/)
|
60
|
+
GetText::RubyParser.parse_lines(file, code, ary)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
GetText::RGetText.add_parser(HamlParser)
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# Temporarily fixes gettext error:
|
2
|
+
# lib/gettext/locale_path.rb:77:in `%': key not found (KeyError)
|
3
|
+
|
4
|
+
if RUBY_VERSION >= "1.9.0"
|
5
|
+
|
6
|
+
module GetText
|
7
|
+
class LocalePath
|
8
|
+
def initialize(name, topdir = nil)
|
9
|
+
@name = name
|
10
|
+
if topdir
|
11
|
+
@locale_paths = ["#{topdir}/%{lang}/LC_MESSAGES/%{name}.mo", "#{topdir}/%{lang}/%{name}.mo"]
|
12
|
+
else
|
13
|
+
@locale_paths = self.class.default_path_rules
|
14
|
+
end
|
15
|
+
@locale_paths.map! {|v| v % {:name => name, :lang => '%{lang}'} }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# PATH_INFO and QUERY_STRING may not be defined when using lighttpd with server.error-handler-404 trick
|
2
|
+
class Rack::Handler::FastCGI
|
3
|
+
class <<self
|
4
|
+
alias rack_serve serve
|
5
|
+
def serve(request, app)
|
6
|
+
env = request.env
|
7
|
+
parts = env['REQUEST_URI'].to_s.split('?')
|
8
|
+
env['SCRIPT_NAME'] = ''
|
9
|
+
env['PATH_INFO'] = parts[0] if env['PATH_INFO'] == ''
|
10
|
+
env['QUERY_STRING'] = parts[1..-1].join('?') if parts.length > 1 && env['QUERY_STRING'] == ''
|
11
|
+
rack_serve(request, app)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module GetText
|
2
|
+
class Reloader < ::Rack::Reloader
|
3
|
+
def initialize(app, path, cooldown=10)
|
4
|
+
@path = path
|
5
|
+
@po = Dir.glob(File.join(@path, '**', '*.po'))
|
6
|
+
@mo = Dir.glob(File.join(@path, '**', '*.mo'))
|
7
|
+
@pot = File.join(@path, 'rbigg.pot') # Used for locking
|
8
|
+
# If there are not translations, give up
|
9
|
+
cooldown = nil unless @po && @mo && @po.size > 0 && @mo.size > 0
|
10
|
+
super(app, cooldown, Stat)
|
11
|
+
end
|
12
|
+
|
13
|
+
def safe_load(file, mtime, stderr = $stderr)
|
14
|
+
@translations += 1
|
15
|
+
stderr.puts "#{self.class}: reloaded `#{FastGettext.text_domain}' translation `#{file}'"
|
16
|
+
ensure
|
17
|
+
@mtimes[file] = mtime
|
18
|
+
end
|
19
|
+
|
20
|
+
def reload!(stderr = $stderr)
|
21
|
+
@translations = 0
|
22
|
+
super
|
23
|
+
if @translations > 0
|
24
|
+
found, stat = safe_stat(@mo.first)
|
25
|
+
if found && stat
|
26
|
+
File.open(@pot, 'r') do |f|
|
27
|
+
# Ensure we don't produce translation twice
|
28
|
+
f.flock(File::LOCK_EX)
|
29
|
+
found, mstat = safe_stat(@mo.first)
|
30
|
+
if found && mstat && mstat.mtime == stat.mtime
|
31
|
+
require 'gettext/tools'
|
32
|
+
Dir.chdir @path do
|
33
|
+
GetText.create_mofiles(:po_root => '.', :mo_root => '.')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
# Reload whole translation
|
37
|
+
FastGettext.add_text_domain(FastGettext.text_domain, :path => @path)
|
38
|
+
FastGettext.current_cache = {}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
module Stat
|
45
|
+
def rotation
|
46
|
+
@po.map{|file|
|
47
|
+
found, stat = safe_stat(file)
|
48
|
+
next unless found and stat and mtime = stat.mtime
|
49
|
+
@cache[file] = found
|
50
|
+
yield(found, mtime)
|
51
|
+
}.compact
|
52
|
+
end
|
53
|
+
|
54
|
+
def safe_stat(file)
|
55
|
+
return unless file
|
56
|
+
stat = ::File.stat(file)
|
57
|
+
return file, stat if stat.file?
|
58
|
+
rescue Errno::ENOENT, Errno::ENOTDIR
|
59
|
+
@cache.delete(file) and false
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# Temporarily fixes Sequel Ruby 1.9 error:
|
2
|
+
# Encoding::CompatibilityError - incompatible character encodings:
|
3
|
+
# UTF-8 and ASCII-8BIT
|
4
|
+
# Since all variables are returned as ASCII-8BIT
|
5
|
+
|
6
|
+
if RUBY_VERSION >= "1.9.0"
|
7
|
+
|
8
|
+
class Sequel::Model
|
9
|
+
def self.load(row)
|
10
|
+
row.values.each{|v| v.force_encoding('utf-8') if v.is_a?(String)}
|
11
|
+
super(row)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
data/lib/sinatra-hat.rb
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'iconv'
|
3
|
+
|
4
|
+
class Integer
|
5
|
+
def minute
|
6
|
+
self * 60
|
7
|
+
end
|
8
|
+
alias minutes minute
|
9
|
+
def hour
|
10
|
+
minute * 60
|
11
|
+
end
|
12
|
+
alias hours hour
|
13
|
+
def day
|
14
|
+
hour * 24
|
15
|
+
end
|
16
|
+
alias days day
|
17
|
+
def week
|
18
|
+
day * 7
|
19
|
+
end
|
20
|
+
alias weeks week
|
21
|
+
def month
|
22
|
+
day * 30
|
23
|
+
end
|
24
|
+
alias months month
|
25
|
+
def year
|
26
|
+
day * 365
|
27
|
+
end
|
28
|
+
alias years year
|
29
|
+
def ago
|
30
|
+
Time.now - self
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class Time
|
35
|
+
def year_start
|
36
|
+
d = (self - (month-1).months - (day-1).days - hour.hours - min.minutes - sec)
|
37
|
+
d - (d.day-1).days - d.hour.hours - d.min.minutes - d.sec
|
38
|
+
end
|
39
|
+
def month_start
|
40
|
+
self - (day-1).days - hour.hours - min.minutes - sec
|
41
|
+
end
|
42
|
+
def week_start
|
43
|
+
self - ((wday + 6) % 7).days - hour.hours - min.minutes - sec
|
44
|
+
end
|
45
|
+
def midnight
|
46
|
+
self - hour.hours - min.minutes - sec
|
47
|
+
end
|
48
|
+
def noon
|
49
|
+
midnight + 12.hours
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class String
|
54
|
+
def mail_utf8_subject
|
55
|
+
# 4.2 http://tools.ietf.org/html/rfc2047
|
56
|
+
'=?UTF-8?Q?'+(self.chomp.gsub(/[^ !-<>-^`-~]/){|m| m.unpack('C*').map{|c| '=%02X' % c}.join}.gsub(/\s/, '_'))+'?='
|
57
|
+
end
|
58
|
+
def cdata
|
59
|
+
"<![CDATA[#{self.gsub(/\]\]>/,']]]]><![CDATA[>')}]]>"
|
60
|
+
end
|
61
|
+
def md5
|
62
|
+
hash = Digest::MD5.new
|
63
|
+
hash << self
|
64
|
+
hash.hexdigest
|
65
|
+
end
|
66
|
+
def sha1
|
67
|
+
hash = Digest::SHA1.new
|
68
|
+
hash << self
|
69
|
+
hash.hexdigest
|
70
|
+
end
|
71
|
+
# This is Pligg style password hash
|
72
|
+
def pwdhash(salt=nil)
|
73
|
+
salt = String.random_password.md5 if salt.nil?
|
74
|
+
salt = salt[0..8]
|
75
|
+
salt+(salt+self).sha1
|
76
|
+
end
|
77
|
+
def excerpt(chars=nil)
|
78
|
+
first = split(/(?:\n\r?){2,}/)[0] || ""
|
79
|
+
return first if chars.nil?
|
80
|
+
words = first.split(' ')
|
81
|
+
pos, count = words.inject([0, 0]) do |c, v|
|
82
|
+
c[1] + v.length < chars ? [c[0] + 1, c[1] + v.length] : c
|
83
|
+
end
|
84
|
+
words[0..pos].join(' ') + ((pos == words.size) ? '' : '…')
|
85
|
+
end
|
86
|
+
def utf8_length
|
87
|
+
unpack('U*').length
|
88
|
+
end
|
89
|
+
def pad(other, extra=0)
|
90
|
+
padding = other.utf8_length - utf8_length
|
91
|
+
padding = 0 if padding < 0
|
92
|
+
' ' * (padding+extra) + self
|
93
|
+
end
|
94
|
+
def self.random_password(length=9, strength=0)
|
95
|
+
vowels = 'aeuy'
|
96
|
+
consonants = 'bdghjmnpqrstvz'
|
97
|
+
consonants += 'BDGHJLMNPQRSTVWXZ' if strength & 1 != 0
|
98
|
+
vowels += 'AEUY' if strength & 2 != 0
|
99
|
+
consonants += '23456789' if strength & 4 != 0
|
100
|
+
consonants += '@#$%' if strength & 8 != 0
|
101
|
+
password = '';
|
102
|
+
alt = rand(2)
|
103
|
+
length.times do
|
104
|
+
password += consonants[rand(consonants.size - 1)].chr if alt != 0
|
105
|
+
password += vowels[rand(vowels.size - 1)].chr if alt == 0
|
106
|
+
alt = 1 - alt
|
107
|
+
end
|
108
|
+
password
|
109
|
+
end
|
110
|
+
def comma_split
|
111
|
+
CSV.parse_line(gsub(/"\s+,/,'",').gsub(/,\s+"/,',"')).collect{|t| t.strip unless t.nil?}.delete_if{|t| t.nil? || t.empty?}
|
112
|
+
end
|
113
|
+
# http://gist.github.com/93045
|
114
|
+
def to_permalink
|
115
|
+
Iconv.iconv('ascii//translit//IGNORE', 'utf-8', self).first.gsub("'", "").gsub(/[^\x00-\x7F]+/, '').gsub(/[^a-zA-Z0-9-]+/, '-').gsub(/--+/, '-').gsub(/^-/, '').gsub(/-$/, '').downcase
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
class Array
|
120
|
+
def comma_join
|
121
|
+
map{|v| s = v.gsub!(/,/,',') || v.gsub!(/"/,'""'); s ? '"'+v+'"' : v}.join(', ')
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
if defined? Rack
|
126
|
+
class Rack::Request
|
127
|
+
def url(path=nil)
|
128
|
+
url = scheme + "://"
|
129
|
+
url << host
|
130
|
+
if scheme == "https" && port != 443 ||
|
131
|
+
scheme == "http" && port != 80
|
132
|
+
url << ":#{port}"
|
133
|
+
end
|
134
|
+
url << (path ? path : fullpath)
|
135
|
+
url
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def silence_warnings
|
141
|
+
old_verbose, $VERBOSE = $VERBOSE, nil
|
142
|
+
yield
|
143
|
+
ensure
|
144
|
+
$VERBOSE = old_verbose
|
145
|
+
end
|
146
|
+
|
147
|
+
if RUBY_VERSION < "1.9.0"
|
148
|
+
class Symbol
|
149
|
+
def to_proc
|
150
|
+
proc { |obj, *args| obj.send(self, *args) }
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# Reload scripts and reset routes on change
|
2
|
+
class Sinatra::Reloader < Rack::Reloader
|
3
|
+
def safe_load(file, mtime, stderr = $stderr)
|
4
|
+
if file == ::Sinatra::Application.app_file
|
5
|
+
::Sinatra::Application.reset!
|
6
|
+
::Sinatra::Application.clear_cache! if ::Sinatra::Application.respond_to? :clear_cache!
|
7
|
+
stderr.puts "#{self.class}: reseting routes and cache"
|
8
|
+
end
|
9
|
+
super
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# Sinatra 0.9.x Haml template cache module
|
2
|
+
|
3
|
+
# Caches Haml templates in Class instance "render_haml_#{template}" methods,
|
4
|
+
# avoiding reparsing and recompiling of the template on every page reload.
|
5
|
+
|
6
|
+
class Sinatra::Base
|
7
|
+
# Override function responsible for calling internal Haml rendering routines
|
8
|
+
def haml(template, options={}, locals={})
|
9
|
+
method = "render_haml_#{template}".to_sym
|
10
|
+
return super(template, options, locals) unless self.respond_to? method
|
11
|
+
locals = options.delete(:locals) || locals || {}
|
12
|
+
if options[:layout] != false
|
13
|
+
__send__(:render_haml_layout, locals) { __send__(method, locals) }
|
14
|
+
else
|
15
|
+
__send__(method, locals)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
def render_haml(template, data, options, locals, &block)
|
19
|
+
method = "render_haml_#{template}".to_sym
|
20
|
+
::Haml::Engine.new(data, options).def_method(self.class, method, *(locals.keys))
|
21
|
+
__send__(method, locals, &block)
|
22
|
+
end
|
23
|
+
def self.clear_cache!
|
24
|
+
instance_methods.grep(/^render_haml_/).each{|m| remove_method m}
|
25
|
+
end
|
26
|
+
def clear_cache!; self.class.clear_cache! end
|
27
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sinatra-hat
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 4
|
10
|
+
version: 0.0.4
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Adam Strzelecki
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-02-21 00:00:00 +01:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: Sinatra Ruby gem extensions for gettext, caching, reloading, etc.
|
23
|
+
email: ono@java.pl
|
24
|
+
executables: []
|
25
|
+
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files:
|
29
|
+
- README.markdown
|
30
|
+
files:
|
31
|
+
- MIT-LICENSE
|
32
|
+
- README.markdown
|
33
|
+
- Rakefile
|
34
|
+
- VERSION
|
35
|
+
- lib/gettext/haml.rb
|
36
|
+
- lib/gettext/haml_parser.rb
|
37
|
+
- lib/gettext/ruby19_fix.rb
|
38
|
+
- lib/rack/fastcgi_fix.rb
|
39
|
+
- lib/rack/gettext_reloader.rb
|
40
|
+
- lib/sequel/utf8_fix.rb
|
41
|
+
- lib/sinatra-hat.rb
|
42
|
+
- lib/sinatra/reloader.rb
|
43
|
+
- lib/sinatra/template_cache.rb
|
44
|
+
- test/sinatra-hat_test.rb
|
45
|
+
- test/test_helper.rb
|
46
|
+
has_rdoc: true
|
47
|
+
homepage: http://github.com/nanoant/sinatra-hat
|
48
|
+
licenses: []
|
49
|
+
|
50
|
+
post_install_message:
|
51
|
+
rdoc_options: []
|
52
|
+
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
hash: 3
|
61
|
+
segments:
|
62
|
+
- 0
|
63
|
+
version: "0"
|
64
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
hash: 3
|
70
|
+
segments:
|
71
|
+
- 0
|
72
|
+
version: "0"
|
73
|
+
requirements: []
|
74
|
+
|
75
|
+
rubyforge_project:
|
76
|
+
rubygems_version: 1.5.2
|
77
|
+
signing_key:
|
78
|
+
specification_version: 3
|
79
|
+
summary: Sinatra Ruby gem extensions for gettext, caching, reloading, etc.
|
80
|
+
test_files:
|
81
|
+
- test/sinatra-hat_test.rb
|
82
|
+
- test/test_helper.rb
|