ramaze 2008.06 → 2008.11
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.
- data/README.markdown +6 -6
- data/Rakefile +33 -3
- data/bin/ramaze +18 -0
- data/doc/CHANGELOG +960 -0
- data/doc/LEGAL +5 -1
- data/doc/meta/announcement.txt +20 -36
- data/doc/tutorial/todolist.html +421 -313
- data/doc/tutorial/todolist.mkd +33 -16
- data/examples/app/blog/spec/blog.rb +3 -3
- data/examples/app/rapaste/controller/paste.rb +8 -1
- data/examples/app/rapaste/model/paste.rb +3 -0
- data/examples/app/rapaste/spec/rapaste.rb +3 -1
- data/examples/app/rapaste/start.rb +3 -2
- data/examples/app/sourceview/public/sourceview.js +2 -2
- data/examples/app/todolist/spec/todolist.rb +6 -6
- data/examples/app/todolist/template/index.xhtml +1 -1
- data/examples/app/whywiki/spec/whywiki.rb +2 -2
- data/examples/app/wikore/spec/wikore.rb +2 -2
- data/examples/app/wikore/src/model.rb +4 -3
- data/examples/app/wiktacular/spec/wiktacular.rb +7 -7
- data/examples/basic/simple.rb +2 -2
- data/examples/helpers/paginate.rb +71 -0
- data/examples/misc/simple_auth.rb +20 -8
- data/lib/proto/controller/init.rb +10 -0
- data/lib/proto/controller/main.rb +1 -3
- data/lib/proto/model/init.rb +4 -0
- data/lib/proto/public/dispatch.fcgi +1 -1
- data/lib/proto/spec/main.rb +2 -1
- data/lib/proto/start.rb +3 -3
- data/lib/proto/start.ru +1 -1
- data/lib/proto/view/error.xhtml +4 -4
- data/lib/ramaze.rb +8 -3
- data/lib/ramaze/action.rb +6 -6
- data/lib/ramaze/adapter.rb +1 -6
- data/lib/ramaze/adapter/base.rb +30 -27
- data/lib/ramaze/adapter/cgi.rb +1 -0
- data/lib/ramaze/cache.rb +1 -3
- data/lib/ramaze/cache/memcached.rb +3 -5
- data/lib/ramaze/contrib/auto_params.rb +2 -2
- data/lib/ramaze/contrib/auto_params/get_args.rb +2 -1
- data/lib/ramaze/contrib/gems.rb +17 -18
- data/lib/ramaze/contrib/gzip_filter.rb +22 -9
- data/lib/ramaze/contrib/maruku_uv.rb +59 -0
- data/lib/ramaze/contrib/profiling.rb +1 -1
- data/lib/ramaze/contrib/rest.rb +16 -13
- data/lib/ramaze/contrib/sequel/create_join.rb +25 -0
- data/lib/ramaze/contrib/sequel/form_field.rb +129 -0
- data/lib/ramaze/contrib/sequel/image.rb +198 -0
- data/lib/ramaze/contrib/sequel/relation.rb +82 -0
- data/lib/ramaze/controller.rb +33 -34
- data/lib/ramaze/controller/resolve.rb +29 -9
- data/lib/ramaze/current.rb +60 -20
- data/lib/ramaze/current/request.rb +8 -7
- data/lib/ramaze/current/response.rb +15 -3
- data/lib/ramaze/current/session/flash.rb +8 -0
- data/lib/ramaze/dispatcher.rb +17 -9
- data/lib/ramaze/dispatcher/action.rb +4 -5
- data/lib/ramaze/dispatcher/directory.rb +1 -1
- data/lib/ramaze/dispatcher/error.rb +4 -4
- data/lib/ramaze/dispatcher/file.rb +4 -4
- data/lib/ramaze/gestalt.rb +15 -20
- data/lib/ramaze/helper/cgi.rb +7 -15
- data/lib/ramaze/helper/formatting.rb +41 -1
- data/lib/ramaze/helper/httpdigest.rb +20 -7
- data/lib/ramaze/helper/link.rb +4 -6
- data/lib/ramaze/helper/paginate.rb +233 -0
- data/lib/ramaze/helper/redirect.rb +1 -1
- data/lib/ramaze/helper/rest.rb +1 -1
- data/lib/ramaze/helper/thread.rb +17 -0
- data/lib/ramaze/helper/ultraviolet.rb +44 -0
- data/lib/ramaze/helper/user.rb +4 -9
- data/lib/ramaze/log.rb +2 -2
- data/lib/ramaze/log/analogger.rb +21 -23
- data/lib/ramaze/log/growl.rb +21 -23
- data/lib/ramaze/log/hub.rb +1 -1
- data/lib/ramaze/log/informer.rb +97 -99
- data/lib/ramaze/log/knotify.rb +14 -16
- data/lib/ramaze/log/logger.rb +11 -13
- data/lib/ramaze/log/logging.rb +61 -63
- data/lib/ramaze/log/rotatinginformer.rb +168 -0
- data/lib/ramaze/log/syslog.rb +41 -31
- data/lib/ramaze/log/xosd.rb +70 -72
- data/lib/ramaze/option.rb +9 -6
- data/lib/ramaze/option/holder.rb +5 -27
- data/lib/ramaze/reloader.rb +186 -0
- data/lib/ramaze/setup.rb +1 -1
- data/lib/ramaze/snippets.rb +13 -0
- data/lib/ramaze/snippets/array/put_within.rb +31 -24
- data/lib/ramaze/snippets/binding/locals.rb +23 -11
- data/lib/ramaze/snippets/dictionary.rb +2 -2
- data/lib/ramaze/snippets/fiber.rb +63 -0
- data/lib/ramaze/snippets/kernel/constant.rb +36 -21
- data/lib/ramaze/snippets/kernel/pretty_inspect.rb +12 -6
- data/lib/ramaze/snippets/numeric/filesize_format.rb +24 -17
- data/lib/ramaze/snippets/numeric/time.rb +63 -0
- data/lib/ramaze/snippets/object/__dir__.rb +29 -0
- data/lib/ramaze/snippets/object/acquire.rb +40 -0
- data/lib/ramaze/snippets/object/instance_variable_defined.rb +16 -5
- data/lib/ramaze/snippets/object/pretty.rb +14 -4
- data/lib/ramaze/snippets/object/scope.rb +14 -7
- data/lib/ramaze/snippets/ordered_set.rb +25 -14
- data/lib/ramaze/snippets/proc/locals.rb +17 -9
- data/lib/ramaze/snippets/ramaze/deprecated.rb +13 -0
- data/lib/ramaze/snippets/ramaze/fiber.rb +24 -0
- data/lib/ramaze/snippets/ramaze/state.rb +86 -0
- data/lib/ramaze/snippets/ramaze/struct.rb +45 -0
- data/lib/ramaze/snippets/string/camel_case.rb +13 -8
- data/lib/ramaze/snippets/string/color.rb +24 -20
- data/lib/ramaze/snippets/string/each.rb +14 -3
- data/lib/ramaze/snippets/string/end_with.rb +20 -0
- data/lib/ramaze/snippets/string/esc.rb +26 -21
- data/lib/ramaze/snippets/string/ord.rb +12 -6
- data/lib/ramaze/snippets/string/snake_case.rb +13 -7
- data/lib/ramaze/snippets/string/start_with.rb +16 -5
- data/lib/ramaze/snippets/string/unindent.rb +23 -15
- data/lib/ramaze/snippets/thread/into.rb +3 -3
- data/lib/ramaze/spec/helper/bacon.rb +5 -5
- data/lib/ramaze/spec/helper/mock_http.rb +1 -1
- data/lib/ramaze/spec/helper/pretty_output.rb +2 -2
- data/lib/ramaze/spec/helper/snippets.rb +8 -0
- data/lib/ramaze/template.rb +4 -1
- data/lib/ramaze/template/ezamar/textpow.syntax +34 -0
- data/lib/ramaze/template/maruku.rb +34 -0
- data/lib/ramaze/template/tagz.rb +2 -2
- data/lib/ramaze/template/xslt.rb +2 -2
- data/lib/ramaze/tool/create.rb +27 -53
- data/lib/ramaze/tool/localize.rb +8 -4
- data/lib/ramaze/tool/mime.rb +11 -1
- data/lib/ramaze/tool/project_creator.rb +110 -0
- data/lib/ramaze/trinity.rb +4 -1
- data/lib/ramaze/version.rb +1 -1
- data/lib/vendor/bacon.rb +323 -0
- data/rake_tasks/gem.rake +10 -1
- data/rake_tasks/maintenance.rake +40 -2
- data/rake_tasks/metric.rake +24 -0
- data/rake_tasks/release.rake +17 -4
- data/rake_tasks/spec.rake +1 -2
- data/ramaze.gemspec +549 -495
- data/spec/contrib/auto_params.rb +3 -3
- data/spec/contrib/profiling.rb +2 -2
- data/spec/examples/simple_auth.rb +2 -2
- data/spec/examples/templates/template_haml.rb +0 -2
- data/spec/ramaze/action/file_cache.rb +22 -0
- data/spec/ramaze/adapter.rb +2 -2
- data/spec/ramaze/controller/actionless_templates.rb +1 -1
- data/spec/ramaze/controller/subclass.rb +15 -0
- data/spec/ramaze/controller/template_resolving.rb +1 -1
- data/spec/ramaze/controller/view/bar.xhtml +1 -0
- data/spec/ramaze/controller/view/base/another.xhtml +1 -0
- data/spec/ramaze/current/session.rb +1 -1
- data/spec/ramaze/dispatcher/file.rb +2 -2
- data/spec/ramaze/helper/aspect.rb +26 -17
- data/spec/ramaze/helper/formatting.rb +13 -0
- data/spec/ramaze/log/informer.rb +10 -10
- data/spec/ramaze/log/syslog.rb +67 -4
- data/spec/ramaze/rewrite.rb +1 -1
- data/spec/ramaze/route.rb +1 -1
- data/spec/ramaze/struct.rb +47 -0
- data/spec/ramaze/template/markaby.rb +1 -1
- data/spec/ramaze/template/tagz.rb +1 -1
- data/spec/snippets/binding/locals.rb +9 -0
- data/spec/snippets/numeric/time.rb +12 -0
- data/spec/snippets/{kernel → object}/__dir__.rb +0 -0
- data/spec/snippets/{kernel → object}/acquire.rb +0 -0
- metadata +90 -81
- data/cache.yaml +0 -7
- data/examples/app/rammit/spec/rammit.rb +0 -31
- data/examples/app/rammit/src/controller/main.rb +0 -3
- data/examples/app/rammit/src/controller/page.rb +0 -16
- data/examples/app/rammit/src/model.rb +0 -33
- data/examples/app/rammit/start.rb +0 -8
- data/examples/app/rammit/template/index.xhtml +0 -14
- data/examples/app/rammit/template/page/view.xhtml +0 -4
- data/lib/ramaze/snippets/kernel/__dir__.rb +0 -23
- data/lib/ramaze/snippets/kernel/acquire.rb +0 -34
- data/lib/ramaze/snippets/object/thread_accessor.rb +0 -5
- data/lib/ramaze/snippets/ramaze/thread_accessor.rb +0 -58
- data/lib/ramaze/snippets/struct/fill.rb +0 -23
- data/lib/ramaze/snippets/struct/values_at.rb +0 -39
- data/lib/ramaze/snippets/symbol/to_proc.rb +0 -24
- data/lib/ramaze/sourcereload.rb +0 -176
- data/spec/snippets/struct/fill.rb +0 -26
- data/spec/snippets/struct/values_at.rb +0 -52
- data/spec/snippets/symbol/to_proc.rb +0 -13
@@ -43,13 +43,11 @@ module Ramaze
|
|
43
43
|
nil
|
44
44
|
end
|
45
45
|
|
46
|
-
#
|
47
|
-
# get_multi, have to investigate this further.
|
48
|
-
#
|
49
|
-
# for now, i'll just use the dumbed down version and ask it
|
50
|
-
# whether it implements this functionality or not.
|
46
|
+
# Fetch for multiple keys at once.
|
51
47
|
|
52
48
|
def get_multi(*keys)
|
49
|
+
# MemCache only responds to get_multi if the memcache-client_extensions gem
|
50
|
+
# is installed, so we check first and resort to another approach if not.
|
53
51
|
if @cache.respond_to?(:get_multi)
|
54
52
|
@cache.get_multi(*keys)
|
55
53
|
else
|
@@ -47,11 +47,11 @@ module Ramaze
|
|
47
47
|
self[:params] = par.map{ |pa|
|
48
48
|
case pa
|
49
49
|
when Array
|
50
|
-
pa.map{|p|
|
50
|
+
pa.map{|p| Rack::Utils.unescape(p)}
|
51
51
|
when nil
|
52
52
|
nil
|
53
53
|
else
|
54
|
-
|
54
|
+
Rack::Utils.unescape(pa)
|
55
55
|
end
|
56
56
|
} unless par.nil?
|
57
57
|
self[:params] ||= []
|
data/lib/ramaze/contrib/gems.rb
CHANGED
@@ -14,8 +14,12 @@ module Ramaze
|
|
14
14
|
@gems << GemStone.new(name, options)
|
15
15
|
end
|
16
16
|
|
17
|
+
# options include:
|
18
|
+
# :install_dir => where to install gems
|
19
|
+
# :extconf => additional options for building extensions
|
20
|
+
|
17
21
|
def options opts = {}
|
18
|
-
@options ||= {
|
22
|
+
@options ||= {}
|
19
23
|
@options.merge! opts unless opts.empty?
|
20
24
|
@options
|
21
25
|
end
|
@@ -31,36 +35,31 @@ module Ramaze
|
|
31
35
|
|
32
36
|
def initialize(name, options = {})
|
33
37
|
@name, @options = name, options
|
38
|
+
require 'rubygems/dependency_installer'
|
39
|
+
@installer = Gem::DependencyInstaller.new(@options)
|
34
40
|
end
|
35
41
|
|
36
42
|
def setup(ran = false)
|
37
|
-
|
38
|
-
Gem.use_paths Gems.options[:install_dir] if Gems.options[:install_dir]
|
39
|
-
|
40
|
-
Gem.activate(name, *[@options[:version]].compact)
|
43
|
+
Gem.activate(name, *[options[:version]].compact)
|
41
44
|
require options[:lib] || name
|
42
45
|
rescue LoadError => error
|
43
46
|
puts error
|
44
47
|
return if ran
|
45
|
-
puts "attempting install"
|
46
48
|
install
|
47
49
|
setup(ran = true)
|
48
50
|
end
|
49
51
|
|
50
52
|
def install
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
cmd << "--no-rdoc" << "--no-ri" unless Gems.options[:docs]
|
56
|
-
cmd << "--install-dir" << Gems.options[:install_dir] if Gems.options[:install_dir]
|
57
|
-
cmd << "--version" << version if version
|
58
|
-
cmd << "--source" << source if source
|
53
|
+
if extconf = (options[:extconf] || Gems.options[:extconf])
|
54
|
+
old_argv = ARGV.clone
|
55
|
+
ARGV.replace extconf.split(' ')
|
56
|
+
end
|
59
57
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
58
|
+
print "Installing #{name}..."
|
59
|
+
@installer.install name, options[:version]
|
60
|
+
puts "done.\n\n"
|
61
|
+
ensure
|
62
|
+
ARGV.replace old_argv if extconf
|
64
63
|
end
|
65
64
|
end
|
66
65
|
end
|
@@ -3,13 +3,22 @@
|
|
3
3
|
|
4
4
|
# gzip_filter.rb
|
5
5
|
#
|
6
|
-
# Use this to compress "large" pages with gzip. All major browsers support
|
7
|
-
#
|
6
|
+
# Use this to compress "large" pages with gzip. All major browsers support
|
7
|
+
# gzipped pages.
|
8
|
+
# This filter brought to you by your friends in #ramaze:
|
9
|
+
# Pistos, manveru, rikur and Kashia.
|
8
10
|
#
|
9
11
|
# Usage, in start.rb:
|
10
12
|
#
|
11
13
|
# require 'ramaze/contrib/gzip_filter'
|
12
14
|
# Ramaze::Dispatcher::Action::FILTER << Ramaze::Filter::Gzip
|
15
|
+
#
|
16
|
+
# Setting options (at any point in your code):
|
17
|
+
#
|
18
|
+
# Ramaze::Filter::Gzip.trait(
|
19
|
+
# :threshold => 1024,
|
20
|
+
# :content_type => /^text\/.+/
|
21
|
+
# )
|
13
22
|
|
14
23
|
require 'zlib'
|
15
24
|
|
@@ -17,8 +26,9 @@ module Ramaze
|
|
17
26
|
module Filter
|
18
27
|
class Gzip
|
19
28
|
|
20
|
-
trait :enabled => true
|
21
|
-
|
29
|
+
trait :enabled => true,
|
30
|
+
:content_type => /^text\/.+/,
|
31
|
+
:threshold => 32768 # bytes
|
22
32
|
|
23
33
|
class << self
|
24
34
|
|
@@ -27,21 +37,24 @@ module Ramaze
|
|
27
37
|
# Enables being plugged into Dispatcher::Action::FILTER
|
28
38
|
|
29
39
|
def call( response, options = {} )
|
30
|
-
return response
|
31
|
-
return response
|
32
|
-
return response if
|
40
|
+
return response unless trait[ :enabled ]
|
41
|
+
return response unless body = response.body
|
42
|
+
return response if body.respond_to?( :read )
|
33
43
|
|
34
44
|
accepts = request.env[ 'HTTP_ACCEPT_ENCODING' ]
|
35
45
|
return response if accepts.nil? || ( accepts !~ /(x-gzip|gzip)/ )
|
36
46
|
|
37
|
-
|
47
|
+
acceptable_size = body.size >= trait[ :threshold ]
|
48
|
+
acceptable_type = response.content_type =~ trait[:content_type]
|
49
|
+
|
50
|
+
if acceptable_type and acceptable_size
|
38
51
|
output = StringIO.new
|
39
52
|
def output.close
|
40
53
|
# Zlib closes the file handle, so we want to circumvent this
|
41
54
|
rewind
|
42
55
|
end
|
43
56
|
gz = Zlib::GzipWriter.new( output )
|
44
|
-
gz.write(
|
57
|
+
gz.write( body )
|
45
58
|
gz.close
|
46
59
|
|
47
60
|
response.body = output.string
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# A hack to make MaRuKu use UltraViolet for highlighting
|
2
|
+
# To specify the style to use use for example:
|
3
|
+
# uv_style: amy
|
4
|
+
# html_use_syntax: true
|
5
|
+
# code_lang: ruby
|
6
|
+
# In the document header area.
|
7
|
+
|
8
|
+
require 'maruku'
|
9
|
+
|
10
|
+
module MaRuKu
|
11
|
+
module Out
|
12
|
+
module HTML
|
13
|
+
def uv_highlight(source, lang, style)
|
14
|
+
require 'uv'
|
15
|
+
|
16
|
+
html = Uv.parse(source, 'xhtml', lang, lines = false, style)
|
17
|
+
|
18
|
+
# Prepare <code> containing <pre>
|
19
|
+
code = Document.new(html, :respect_whitespace => :all).root
|
20
|
+
code.name = 'code'
|
21
|
+
code.attributes['class'] = lang
|
22
|
+
code.attributes['lang'] = lang
|
23
|
+
|
24
|
+
# Prepare <pre>
|
25
|
+
pre = Element.new('pre')
|
26
|
+
pre << code
|
27
|
+
pre.attributes['class'] = style
|
28
|
+
pre
|
29
|
+
rescue => ex
|
30
|
+
puts ex
|
31
|
+
to_html_code_using_pre(source)
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_html_code
|
35
|
+
source = self.raw_code
|
36
|
+
use_syntax = get_setting(:html_use_syntax)
|
37
|
+
uv_style = get_setting(:uv_style)
|
38
|
+
|
39
|
+
lang = self.attributes[:lang] || @doc.attributes[:code_lang]
|
40
|
+
lang ||= 'ruby' if attributes[:ruby]
|
41
|
+
|
42
|
+
# we always use syntax highlighting, this is a doc wiki
|
43
|
+
if lang and use_syntax
|
44
|
+
element = uv_highlight(source, lang, uv_style)
|
45
|
+
else
|
46
|
+
element = to_html_code_using_pre(source)
|
47
|
+
end
|
48
|
+
|
49
|
+
color = get_setting(:code_background_color)
|
50
|
+
|
51
|
+
if color != Globals[:code_background_color]
|
52
|
+
element.attributes['style'] = "background-color: #{color};"
|
53
|
+
end
|
54
|
+
|
55
|
+
add_ws element
|
56
|
+
end
|
57
|
+
end # HTML
|
58
|
+
end # Out
|
59
|
+
end # MaRuKu
|
data/lib/ramaze/contrib/rest.rb
CHANGED
@@ -1,14 +1,17 @@
|
|
1
|
-
Ramaze::
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
1
|
+
Ramaze::Rewrite['REST dispatch'] = lambda do |path, request|
|
2
|
+
path << '/' unless path[-1] == '/'
|
3
|
+
|
4
|
+
method = if request.request_method == 'POST' and request.params.has_key?('method')
|
5
|
+
request.params['method'].upcase
|
6
|
+
else
|
7
|
+
request.request_method
|
8
|
+
end
|
9
|
+
|
10
|
+
case method
|
11
|
+
when 'GET' then path << 'show/'
|
12
|
+
when 'POST' then path << 'create/'
|
13
|
+
when 'PUT' then path << 'update/'
|
14
|
+
when 'DELETE' then path << 'destroy/'
|
15
|
+
else path
|
13
16
|
end
|
14
|
-
|
17
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'sequel'
|
2
|
+
|
3
|
+
module Sequel
|
4
|
+
class Model
|
5
|
+
# Force join table generation
|
6
|
+
#
|
7
|
+
# Usage:
|
8
|
+
# User.create_join(Article, 'articles_users')
|
9
|
+
# # or let the method figure out the correct join table using sequel
|
10
|
+
# # conventions.
|
11
|
+
# User.create_join(Article)
|
12
|
+
def self.create_join(to, name = nil)
|
13
|
+
from = self
|
14
|
+
name ||= [table_name.to_s, to.table_name.to_s].sort.join('_')
|
15
|
+
from_key = "#{from.table_name.to_s.singularize}_id"
|
16
|
+
to_key = "#{to.table_name.to_s.singularize}_id"
|
17
|
+
|
18
|
+
db.create_table! name do
|
19
|
+
primary_key :id
|
20
|
+
foreign_key from_key, :class => from
|
21
|
+
foreign_key to_key, :class => to
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'ramaze/gestalt'
|
2
|
+
|
3
|
+
# job = Job[4]
|
4
|
+
# puts CGI::pretty(FormField.new(job, :contract, show_errors = true, Job::CONTRACTS).to_s)
|
5
|
+
|
6
|
+
class FormField
|
7
|
+
attr_accessor :this, :field, :show_errors, :hint, :db_type, :id, :value
|
8
|
+
|
9
|
+
# show_errors may be a number indicating how many errors it should display at
|
10
|
+
# maximum, 0 displays none, -1 all
|
11
|
+
|
12
|
+
def initialize(this, field, show_errors = true, hint = nil)
|
13
|
+
@this, @field, @show_errors, @hint =
|
14
|
+
this, field.to_sym, show_errors, hint
|
15
|
+
@db_type = db_type
|
16
|
+
@id = "form_#{@field}"
|
17
|
+
@value = this.send(@field)
|
18
|
+
end
|
19
|
+
|
20
|
+
def db_type
|
21
|
+
if field_schema = this.class.db_schema[field]
|
22
|
+
field_schema[:db_type]
|
23
|
+
else
|
24
|
+
nil
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_s
|
29
|
+
unless label = @this.class::FORM_LABEL[field]
|
30
|
+
raise("No FORM_LABEL for %p on %p" % [field, @this.class])
|
31
|
+
end
|
32
|
+
|
33
|
+
label += ':'
|
34
|
+
id = @id
|
35
|
+
_self = self
|
36
|
+
|
37
|
+
Ramaze::Gestalt.build{
|
38
|
+
div(:class => :pair){
|
39
|
+
label(:for => id){ label }
|
40
|
+
_self.build_tag(self)
|
41
|
+
_self.build_errors(self)
|
42
|
+
}
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
def password(gestalt)
|
47
|
+
gestalt.input(@args.merge :type => :password, :value => value)
|
48
|
+
end
|
49
|
+
|
50
|
+
def checkbox(gestalt)
|
51
|
+
@args[:checked] = :checked if value
|
52
|
+
gestalt.input(@args.merge :type => :checkbox)
|
53
|
+
end
|
54
|
+
|
55
|
+
def select(gestalt)
|
56
|
+
gestalt.select @args do
|
57
|
+
v = value.to_s
|
58
|
+
hint.each do |h|
|
59
|
+
h = h.to_s
|
60
|
+
if h == v
|
61
|
+
gestalt.option(:value => h, :selected => :selected){ h }
|
62
|
+
else
|
63
|
+
gestalt.option(:value => h){ h }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def input(gestalt)
|
70
|
+
gestalt.input(@args.merge :type => :text, :value => value)
|
71
|
+
end
|
72
|
+
|
73
|
+
def file(gestalt)
|
74
|
+
gestalt.input(@args.merge :type => :file)
|
75
|
+
end
|
76
|
+
|
77
|
+
def textarea(gestalt)
|
78
|
+
gestalt.textarea(@args){ value.to_s }
|
79
|
+
end
|
80
|
+
|
81
|
+
def build_tag(gestalt)
|
82
|
+
@args = {:id => id, :name => field}
|
83
|
+
|
84
|
+
case hint
|
85
|
+
when :password
|
86
|
+
password(gestalt)
|
87
|
+
when :boolean, :checkbox
|
88
|
+
checkbox(gestalt)
|
89
|
+
when :textarea
|
90
|
+
textarea(gestalt)
|
91
|
+
when :file
|
92
|
+
file(gestalt)
|
93
|
+
when Array, Range
|
94
|
+
select(gestalt)
|
95
|
+
else
|
96
|
+
case db_type
|
97
|
+
when 'varchar', 'integer'
|
98
|
+
input(gestalt)
|
99
|
+
when 'boolean'
|
100
|
+
checkbox(gestalt)
|
101
|
+
when 'string'
|
102
|
+
textarea(gestalt)
|
103
|
+
else
|
104
|
+
raise "Unsupported type: (#{db_type || hint} : #{field})"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def build_errors(gestalt)
|
110
|
+
each_error do |error|
|
111
|
+
gestalt.span(:class => :error){ error }
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# TODO: suggest 'validated?' feature to sequel
|
116
|
+
def each_error(&block)
|
117
|
+
return unless show_errors
|
118
|
+
|
119
|
+
this.validate if this.errors.empty?
|
120
|
+
this.errors[field].first(show_errors).each(&block)
|
121
|
+
end
|
122
|
+
|
123
|
+
module Model
|
124
|
+
def form_field(field, hint = nil)
|
125
|
+
show_errors = Ramaze::Request.current.post? ? 1 : 0
|
126
|
+
FormField.new(self, field, show_errors, hint).to_s
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,198 @@
|
|
1
|
+
# Copyright (c) 2008 Michael Fellinger m.fellinger@gmail.com
|
2
|
+
# All files in this distribution are subject to the terms of the Ruby license.
|
3
|
+
|
4
|
+
# Scaffold image models utilizing thumbnailing and Ramaze integration.
|
5
|
+
# Resizing is done by ImageScience.
|
6
|
+
#
|
7
|
+
# Usage:
|
8
|
+
# class Avatar < Sequel::Model
|
9
|
+
# IMAGE = {
|
10
|
+
# # specifies belongs_to, will create relation and foreign key
|
11
|
+
#
|
12
|
+
# :owner => :User,
|
13
|
+
#
|
14
|
+
#
|
15
|
+
# # Remove original and thumbnails on Avatar#destroy
|
16
|
+
#
|
17
|
+
# :cleanup => true,
|
18
|
+
#
|
19
|
+
#
|
20
|
+
# # Algorithm to use in ImageScience
|
21
|
+
# #
|
22
|
+
# # * resize(width, height)
|
23
|
+
# # Resizes the image to +width+ and +height+ using a cubic-bspline
|
24
|
+
# # filter.
|
25
|
+
# #
|
26
|
+
# # * thumbnail(size)
|
27
|
+
# # Creates a proportional thumbnail of the image scaled so its
|
28
|
+
# # longest edge is resized to +size+.
|
29
|
+
# #
|
30
|
+
# # * cropped_thumbnail(size)
|
31
|
+
# # Creates a square thumbnail of the image cropping the longest edge
|
32
|
+
# # to match the shortest edge, resizes to +size+.
|
33
|
+
#
|
34
|
+
# :agorithm => :thumbnail,
|
35
|
+
#
|
36
|
+
#
|
37
|
+
# # Key specifies the filename and accessors, value are arguments to the
|
38
|
+
# # algorithm
|
39
|
+
#
|
40
|
+
# :sizes => {
|
41
|
+
# :small => 150,
|
42
|
+
# :medium => 300,
|
43
|
+
# :large => 600
|
44
|
+
# }
|
45
|
+
# }
|
46
|
+
#
|
47
|
+
# # Perform the scaffold
|
48
|
+
# include SequelImage
|
49
|
+
# end
|
50
|
+
|
51
|
+
module SequelImage
|
52
|
+
def self.included(model)
|
53
|
+
args = model::IMAGE
|
54
|
+
set_foreign_key = args[:foreign_key] || "#{args[:owner]}_id".downcase.to_sym
|
55
|
+
set_belongs_to = args[:belongs_to] || args[:owner].to_s.downcase.to_sym
|
56
|
+
|
57
|
+
# Define schema
|
58
|
+
model.set_schema do
|
59
|
+
primary_key :id
|
60
|
+
|
61
|
+
varchar :original # path to the original image
|
62
|
+
varchar :mime, :size => 22 # average of /etc/mime.types
|
63
|
+
|
64
|
+
time :created_at
|
65
|
+
time :updated_at
|
66
|
+
|
67
|
+
foreign_key set_foreign_key
|
68
|
+
end
|
69
|
+
|
70
|
+
# Define Relations
|
71
|
+
model.belongs_to set_belongs_to
|
72
|
+
|
73
|
+
# Define Hooks
|
74
|
+
model.send(:hooks).clear
|
75
|
+
|
76
|
+
model.before_create do
|
77
|
+
generate_thumbnails
|
78
|
+
self.created_at = Time.now
|
79
|
+
end
|
80
|
+
|
81
|
+
model.before_save do
|
82
|
+
self.updated_at = Time.now
|
83
|
+
end
|
84
|
+
|
85
|
+
model.before_destroy do
|
86
|
+
cleanup if conf[:cleanup]
|
87
|
+
end
|
88
|
+
|
89
|
+
# Define singleton methods
|
90
|
+
model.extend(SingletonMethods)
|
91
|
+
|
92
|
+
# Define instance methods
|
93
|
+
model.send(:include,
|
94
|
+
InstanceMethods,
|
95
|
+
Ramaze::Helper::CGI,
|
96
|
+
Ramaze::Helper::Link)
|
97
|
+
|
98
|
+
args[:sizes].each do |size, *args|
|
99
|
+
model.send(:define_method, size){ public_file(size) }
|
100
|
+
model.send(:define_method, "#{size}_url"){ file(size) }
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
module SingletonMethods
|
105
|
+
def store(file, uid, hash = {})
|
106
|
+
image = new(hash)
|
107
|
+
|
108
|
+
type = file[:type]
|
109
|
+
filename = file[:filename]
|
110
|
+
tempfile = file[:tempfile]
|
111
|
+
raise ArgumentError, 'Empty tempfile' if tempfile.size == 0
|
112
|
+
|
113
|
+
ext = Ramaze::Tool::MIME.ext_for(type)
|
114
|
+
image.mime = type
|
115
|
+
target_name = image.next_name(File.basename(filename, File.extname(filename)), ext)
|
116
|
+
target_path = File.join(image.public_root, image.path, target_name)
|
117
|
+
|
118
|
+
FileUtils.mkdir_p(File.dirname(target_path))
|
119
|
+
FileUtils.cp(tempfile.path, target_path)
|
120
|
+
|
121
|
+
image.original = target_path
|
122
|
+
image.save
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
module InstanceMethods
|
127
|
+
def file(size = nil)
|
128
|
+
File.join('/', path, filename(size))
|
129
|
+
end
|
130
|
+
|
131
|
+
def public_file(size)
|
132
|
+
File.join(public_path, filename(size))
|
133
|
+
end
|
134
|
+
|
135
|
+
def public_path
|
136
|
+
File.join(public_root, path)
|
137
|
+
end
|
138
|
+
|
139
|
+
def path
|
140
|
+
conf[:path] || conf[:owner].to_s.downcase
|
141
|
+
end
|
142
|
+
|
143
|
+
def next_name(uid, ext)
|
144
|
+
uid = uid.to_s.scan(%r![^\\/'".:?&;\s]+!).join('-')
|
145
|
+
"#{uid}#{ext}"
|
146
|
+
end
|
147
|
+
|
148
|
+
def basename
|
149
|
+
File.basename(original, File.extname(original))
|
150
|
+
end
|
151
|
+
|
152
|
+
def public_root
|
153
|
+
Ramaze::Global.public_root
|
154
|
+
end
|
155
|
+
|
156
|
+
def filename(size)
|
157
|
+
if size
|
158
|
+
"#{basename}_#{size}.png"
|
159
|
+
else
|
160
|
+
"#{basename}.png"
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def conf
|
165
|
+
self.class::IMAGE
|
166
|
+
end
|
167
|
+
|
168
|
+
def cleanup
|
169
|
+
conf[:sizes].each do |name, args|
|
170
|
+
out = public_file(name)
|
171
|
+
Ramaze::Log.debug "Remove Thumbnail: #{out}"
|
172
|
+
FileUtils.rm_f(out)
|
173
|
+
end
|
174
|
+
|
175
|
+
Ramaze::Log.debug "Remove original: #{original}"
|
176
|
+
FileUtils.rm_f(original)
|
177
|
+
end
|
178
|
+
|
179
|
+
def generate_thumbnails
|
180
|
+
FileUtils.mkdir_p(public_path)
|
181
|
+
|
182
|
+
sizes, algorithm = conf.values_at(:sizes, :algorithm)
|
183
|
+
|
184
|
+
ImageScience.with_image(original) do |img|
|
185
|
+
Ramaze::Log.debug "Process original: #{original}"
|
186
|
+
|
187
|
+
sizes.each do |name, args|
|
188
|
+
out = public_file(name)
|
189
|
+
Ramaze::Log.debug "Generate Thumbnail: #{out}"
|
190
|
+
|
191
|
+
img.send(algorithm, *args) do |thumb|
|
192
|
+
thumb.save(out)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|