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.
Files changed (184) hide show
  1. data/README.markdown +6 -6
  2. data/Rakefile +33 -3
  3. data/bin/ramaze +18 -0
  4. data/doc/CHANGELOG +960 -0
  5. data/doc/LEGAL +5 -1
  6. data/doc/meta/announcement.txt +20 -36
  7. data/doc/tutorial/todolist.html +421 -313
  8. data/doc/tutorial/todolist.mkd +33 -16
  9. data/examples/app/blog/spec/blog.rb +3 -3
  10. data/examples/app/rapaste/controller/paste.rb +8 -1
  11. data/examples/app/rapaste/model/paste.rb +3 -0
  12. data/examples/app/rapaste/spec/rapaste.rb +3 -1
  13. data/examples/app/rapaste/start.rb +3 -2
  14. data/examples/app/sourceview/public/sourceview.js +2 -2
  15. data/examples/app/todolist/spec/todolist.rb +6 -6
  16. data/examples/app/todolist/template/index.xhtml +1 -1
  17. data/examples/app/whywiki/spec/whywiki.rb +2 -2
  18. data/examples/app/wikore/spec/wikore.rb +2 -2
  19. data/examples/app/wikore/src/model.rb +4 -3
  20. data/examples/app/wiktacular/spec/wiktacular.rb +7 -7
  21. data/examples/basic/simple.rb +2 -2
  22. data/examples/helpers/paginate.rb +71 -0
  23. data/examples/misc/simple_auth.rb +20 -8
  24. data/lib/proto/controller/init.rb +10 -0
  25. data/lib/proto/controller/main.rb +1 -3
  26. data/lib/proto/model/init.rb +4 -0
  27. data/lib/proto/public/dispatch.fcgi +1 -1
  28. data/lib/proto/spec/main.rb +2 -1
  29. data/lib/proto/start.rb +3 -3
  30. data/lib/proto/start.ru +1 -1
  31. data/lib/proto/view/error.xhtml +4 -4
  32. data/lib/ramaze.rb +8 -3
  33. data/lib/ramaze/action.rb +6 -6
  34. data/lib/ramaze/adapter.rb +1 -6
  35. data/lib/ramaze/adapter/base.rb +30 -27
  36. data/lib/ramaze/adapter/cgi.rb +1 -0
  37. data/lib/ramaze/cache.rb +1 -3
  38. data/lib/ramaze/cache/memcached.rb +3 -5
  39. data/lib/ramaze/contrib/auto_params.rb +2 -2
  40. data/lib/ramaze/contrib/auto_params/get_args.rb +2 -1
  41. data/lib/ramaze/contrib/gems.rb +17 -18
  42. data/lib/ramaze/contrib/gzip_filter.rb +22 -9
  43. data/lib/ramaze/contrib/maruku_uv.rb +59 -0
  44. data/lib/ramaze/contrib/profiling.rb +1 -1
  45. data/lib/ramaze/contrib/rest.rb +16 -13
  46. data/lib/ramaze/contrib/sequel/create_join.rb +25 -0
  47. data/lib/ramaze/contrib/sequel/form_field.rb +129 -0
  48. data/lib/ramaze/contrib/sequel/image.rb +198 -0
  49. data/lib/ramaze/contrib/sequel/relation.rb +82 -0
  50. data/lib/ramaze/controller.rb +33 -34
  51. data/lib/ramaze/controller/resolve.rb +29 -9
  52. data/lib/ramaze/current.rb +60 -20
  53. data/lib/ramaze/current/request.rb +8 -7
  54. data/lib/ramaze/current/response.rb +15 -3
  55. data/lib/ramaze/current/session/flash.rb +8 -0
  56. data/lib/ramaze/dispatcher.rb +17 -9
  57. data/lib/ramaze/dispatcher/action.rb +4 -5
  58. data/lib/ramaze/dispatcher/directory.rb +1 -1
  59. data/lib/ramaze/dispatcher/error.rb +4 -4
  60. data/lib/ramaze/dispatcher/file.rb +4 -4
  61. data/lib/ramaze/gestalt.rb +15 -20
  62. data/lib/ramaze/helper/cgi.rb +7 -15
  63. data/lib/ramaze/helper/formatting.rb +41 -1
  64. data/lib/ramaze/helper/httpdigest.rb +20 -7
  65. data/lib/ramaze/helper/link.rb +4 -6
  66. data/lib/ramaze/helper/paginate.rb +233 -0
  67. data/lib/ramaze/helper/redirect.rb +1 -1
  68. data/lib/ramaze/helper/rest.rb +1 -1
  69. data/lib/ramaze/helper/thread.rb +17 -0
  70. data/lib/ramaze/helper/ultraviolet.rb +44 -0
  71. data/lib/ramaze/helper/user.rb +4 -9
  72. data/lib/ramaze/log.rb +2 -2
  73. data/lib/ramaze/log/analogger.rb +21 -23
  74. data/lib/ramaze/log/growl.rb +21 -23
  75. data/lib/ramaze/log/hub.rb +1 -1
  76. data/lib/ramaze/log/informer.rb +97 -99
  77. data/lib/ramaze/log/knotify.rb +14 -16
  78. data/lib/ramaze/log/logger.rb +11 -13
  79. data/lib/ramaze/log/logging.rb +61 -63
  80. data/lib/ramaze/log/rotatinginformer.rb +168 -0
  81. data/lib/ramaze/log/syslog.rb +41 -31
  82. data/lib/ramaze/log/xosd.rb +70 -72
  83. data/lib/ramaze/option.rb +9 -6
  84. data/lib/ramaze/option/holder.rb +5 -27
  85. data/lib/ramaze/reloader.rb +186 -0
  86. data/lib/ramaze/setup.rb +1 -1
  87. data/lib/ramaze/snippets.rb +13 -0
  88. data/lib/ramaze/snippets/array/put_within.rb +31 -24
  89. data/lib/ramaze/snippets/binding/locals.rb +23 -11
  90. data/lib/ramaze/snippets/dictionary.rb +2 -2
  91. data/lib/ramaze/snippets/fiber.rb +63 -0
  92. data/lib/ramaze/snippets/kernel/constant.rb +36 -21
  93. data/lib/ramaze/snippets/kernel/pretty_inspect.rb +12 -6
  94. data/lib/ramaze/snippets/numeric/filesize_format.rb +24 -17
  95. data/lib/ramaze/snippets/numeric/time.rb +63 -0
  96. data/lib/ramaze/snippets/object/__dir__.rb +29 -0
  97. data/lib/ramaze/snippets/object/acquire.rb +40 -0
  98. data/lib/ramaze/snippets/object/instance_variable_defined.rb +16 -5
  99. data/lib/ramaze/snippets/object/pretty.rb +14 -4
  100. data/lib/ramaze/snippets/object/scope.rb +14 -7
  101. data/lib/ramaze/snippets/ordered_set.rb +25 -14
  102. data/lib/ramaze/snippets/proc/locals.rb +17 -9
  103. data/lib/ramaze/snippets/ramaze/deprecated.rb +13 -0
  104. data/lib/ramaze/snippets/ramaze/fiber.rb +24 -0
  105. data/lib/ramaze/snippets/ramaze/state.rb +86 -0
  106. data/lib/ramaze/snippets/ramaze/struct.rb +45 -0
  107. data/lib/ramaze/snippets/string/camel_case.rb +13 -8
  108. data/lib/ramaze/snippets/string/color.rb +24 -20
  109. data/lib/ramaze/snippets/string/each.rb +14 -3
  110. data/lib/ramaze/snippets/string/end_with.rb +20 -0
  111. data/lib/ramaze/snippets/string/esc.rb +26 -21
  112. data/lib/ramaze/snippets/string/ord.rb +12 -6
  113. data/lib/ramaze/snippets/string/snake_case.rb +13 -7
  114. data/lib/ramaze/snippets/string/start_with.rb +16 -5
  115. data/lib/ramaze/snippets/string/unindent.rb +23 -15
  116. data/lib/ramaze/snippets/thread/into.rb +3 -3
  117. data/lib/ramaze/spec/helper/bacon.rb +5 -5
  118. data/lib/ramaze/spec/helper/mock_http.rb +1 -1
  119. data/lib/ramaze/spec/helper/pretty_output.rb +2 -2
  120. data/lib/ramaze/spec/helper/snippets.rb +8 -0
  121. data/lib/ramaze/template.rb +4 -1
  122. data/lib/ramaze/template/ezamar/textpow.syntax +34 -0
  123. data/lib/ramaze/template/maruku.rb +34 -0
  124. data/lib/ramaze/template/tagz.rb +2 -2
  125. data/lib/ramaze/template/xslt.rb +2 -2
  126. data/lib/ramaze/tool/create.rb +27 -53
  127. data/lib/ramaze/tool/localize.rb +8 -4
  128. data/lib/ramaze/tool/mime.rb +11 -1
  129. data/lib/ramaze/tool/project_creator.rb +110 -0
  130. data/lib/ramaze/trinity.rb +4 -1
  131. data/lib/ramaze/version.rb +1 -1
  132. data/lib/vendor/bacon.rb +323 -0
  133. data/rake_tasks/gem.rake +10 -1
  134. data/rake_tasks/maintenance.rake +40 -2
  135. data/rake_tasks/metric.rake +24 -0
  136. data/rake_tasks/release.rake +17 -4
  137. data/rake_tasks/spec.rake +1 -2
  138. data/ramaze.gemspec +549 -495
  139. data/spec/contrib/auto_params.rb +3 -3
  140. data/spec/contrib/profiling.rb +2 -2
  141. data/spec/examples/simple_auth.rb +2 -2
  142. data/spec/examples/templates/template_haml.rb +0 -2
  143. data/spec/ramaze/action/file_cache.rb +22 -0
  144. data/spec/ramaze/adapter.rb +2 -2
  145. data/spec/ramaze/controller/actionless_templates.rb +1 -1
  146. data/spec/ramaze/controller/subclass.rb +15 -0
  147. data/spec/ramaze/controller/template_resolving.rb +1 -1
  148. data/spec/ramaze/controller/view/bar.xhtml +1 -0
  149. data/spec/ramaze/controller/view/base/another.xhtml +1 -0
  150. data/spec/ramaze/current/session.rb +1 -1
  151. data/spec/ramaze/dispatcher/file.rb +2 -2
  152. data/spec/ramaze/helper/aspect.rb +26 -17
  153. data/spec/ramaze/helper/formatting.rb +13 -0
  154. data/spec/ramaze/log/informer.rb +10 -10
  155. data/spec/ramaze/log/syslog.rb +67 -4
  156. data/spec/ramaze/rewrite.rb +1 -1
  157. data/spec/ramaze/route.rb +1 -1
  158. data/spec/ramaze/struct.rb +47 -0
  159. data/spec/ramaze/template/markaby.rb +1 -1
  160. data/spec/ramaze/template/tagz.rb +1 -1
  161. data/spec/snippets/binding/locals.rb +9 -0
  162. data/spec/snippets/numeric/time.rb +12 -0
  163. data/spec/snippets/{kernel → object}/__dir__.rb +0 -0
  164. data/spec/snippets/{kernel → object}/acquire.rb +0 -0
  165. metadata +90 -81
  166. data/cache.yaml +0 -7
  167. data/examples/app/rammit/spec/rammit.rb +0 -31
  168. data/examples/app/rammit/src/controller/main.rb +0 -3
  169. data/examples/app/rammit/src/controller/page.rb +0 -16
  170. data/examples/app/rammit/src/model.rb +0 -33
  171. data/examples/app/rammit/start.rb +0 -8
  172. data/examples/app/rammit/template/index.xhtml +0 -14
  173. data/examples/app/rammit/template/page/view.xhtml +0 -4
  174. data/lib/ramaze/snippets/kernel/__dir__.rb +0 -23
  175. data/lib/ramaze/snippets/kernel/acquire.rb +0 -34
  176. data/lib/ramaze/snippets/object/thread_accessor.rb +0 -5
  177. data/lib/ramaze/snippets/ramaze/thread_accessor.rb +0 -58
  178. data/lib/ramaze/snippets/struct/fill.rb +0 -23
  179. data/lib/ramaze/snippets/struct/values_at.rb +0 -39
  180. data/lib/ramaze/snippets/symbol/to_proc.rb +0 -24
  181. data/lib/ramaze/sourcereload.rb +0 -176
  182. data/spec/snippets/struct/fill.rb +0 -26
  183. data/spec/snippets/struct/values_at.rb +0 -52
  184. data/spec/snippets/symbol/to_proc.rb +0 -13
@@ -43,13 +43,11 @@ module Ramaze
43
43
  nil
44
44
  end
45
45
 
46
- # out of some reason MemCache sometimes doesn't respond to
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| CGI.unescape(p.to_s)}
50
+ pa.map{|p| Rack::Utils.unescape(p)}
51
51
  when nil
52
52
  nil
53
53
  else
54
- CGI.unescape(pa.to_s)
54
+ Rack::Utils.unescape(pa)
55
55
  end
56
56
  } unless par.nil?
57
57
  self[:params] ||= []
@@ -1,5 +1,6 @@
1
1
  # from merb/core_ext/get_args.rb
2
2
  begin
3
+ require 'parse_tree'
3
4
  require 'ruby2ruby'
4
5
 
5
6
  class ParseTreeArray < Array
@@ -54,4 +55,4 @@ begin
54
55
  include GetArgs
55
56
  end
56
57
  rescue LoadError
57
- end
58
+ end
@@ -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 ||= { :docs => true }
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
- # rubygems resets the path after each successful install
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
- require 'rubygems/gem_runner'
52
- version, source = options.values_at(:version, :source)
53
-
54
- cmd = %w[install] << name
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
- puts cmd * ' '
61
- Gem::GemRunner.new.run(cmd)
62
- rescue Gem::SystemExitException => e
63
- raise unless e.exit_code == 0
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 gzipped pages.
7
- # This filter brought to you by your friends in #ramaze: Pistos, manveru, rikur and Kashia.
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
- trait :threshold => 32768 # bytes
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 if not trait[ :enabled ]
31
- return response if response.body.nil?
32
- return response if response.body.respond_to?( :read )
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
- if response.content_type == 'text/html' && response.body.size > trait[ :threshold ]
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( response.body )
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
@@ -1,7 +1,7 @@
1
1
  require "ruby-prof"
2
2
 
3
3
  module Ramaze
4
- module Dispatcher
4
+ class Dispatcher
5
5
  class ActionProfiler < Action
6
6
  def self.call(path)
7
7
  if RubyProf.running?
@@ -1,14 +1,17 @@
1
- Ramaze::Route['REST dispatch'] = lambda{|path, request|
2
- case request.request_method
3
- when 'GET'
4
- path << 'show/'
5
- when 'POST'
6
- path << 'create/'
7
- when 'PUT'
8
- path << 'update/'
9
- when 'DELETE'
10
- path << 'destroy/'
11
- else
12
- path
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