/ emacs.d / rails / rails-snippets-feature.el
rails-snippets-feature.el
  1  ;;; rails-snippets-feature.el --- snippets for rails related modes
  2  
  3  ;; Copyright (C) 2006 Dmitry Galinsky <dima dot exe at gmail dot com>
  4  
  5  ;; Authors: Dmitry Galinsky <dima dot exe at gmail dot com>,
  6  
  7  ;; Keywords: ruby rails languages oop
  8  ;; $URL: svn+ssh://rubyforge/var/svn/emacs-rails/trunk/rails-snippets.el $
  9  ;; $Id: rails-snippets.el 155 2007-04-01 17:37:48Z dimaexe $
 10  
 11  ;;; License
 12  
 13  ;; This program is free software; you can redistribute it and/or
 14  ;; modify it under the terms of the GNU General Public License
 15  ;; as published by the Free Software Foundation; either version 2
 16  ;; of the License, or (at your option) any later version.
 17  
 18  ;; This program is distributed in the hope that it will be useful,
 19  ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
 20  ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 21  ;; GNU General Public License for more details.
 22  
 23  ;; You should have received a copy of the GNU General Public License
 24  ;; along with this program; if not, write to the Free Software
 25  ;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 26  
 27  (require 'snippet)
 28  
 29  (defconst rails-snippets-feature:list
 30    '((0 "ruby")
 31      (1 "loops" ruby-mode-abbrev-table
 32         ("while" "while $${condition}\n$>$.\nend$>" "while ... end")
 33         ("when" "when $${condition}\n$>$." "when ...")
 34         ("w" "attr_writer :$${attr_names}" "attr_writer ...")
 35         ("upt" "upto($${0}) { |$${n}|$. }" "upto(1.0/0.0) { |n| ... }")
 36         ("until" "until $${condition}\n$>$.\nend$>" "until ... end")
 37         ("tim" "times { |$${n}|$. }" "times { |n| ... }")
 38         ("ste" "step($${2}) { |$${n}|$. }" "step(2) { |e| ... }")
 39         ("forin" "for $${element} in $${collection}\n$>$${element}.$.\nend$>" "for ... in ... end")
 40         ("dow" "downto($${0}) { |$${n}|$. }" "downto(0) { |n| ... }")) ; loops
 41      (1 "general" ruby-mode-abbrev-table
 42         ("ha" "{ $>:$. }" "{ :key => 'value' }")
 43         (":"  ":$${key} => '$${value}'" ":key => 'value'")
 44         ("yl" "File.open($${yaml}) { |$${file}| YAML.load($${file}) }" "YAML.load(file)")
 45         ("yd" "File.open($${yaml}, \"w\") { |$${file}| YAML.dump($${obj}, $${file}) }" "YAML.dump(..., file)")
 46         ("y" " :yields: $${arguments}" ":yields:")
 47         ("verren" "verify :only => [:$${1}], :method => :post, :render => {:status => 500, :text => \"use HTTP-POST\"}\n" "verify -- render")
 48         ("verred" "verify :only => [:$${1}], :session => :user, :params => :id, :redirect_to => {:action => '$${index}'}\n" "verify -- redirect")
 49         ("tra" "transaction$${1} { $. }" "transaction( ... ) { ... }")
 50         ("sub" "sub(/$${pattern}/) { |$${match}|$. }" "sub(/.../) { |match| ... }")
 51         ("sca" "scan(/$${pattern}/) { |$${match}| $. }" "scan(/.../) { |match| ... }")
 52         ("rep" "results.report(\"$${name}:\") { TESTS.times { $. } }" "results.report(...) { ... }")
 53         ("rb" "#!/usr/bin/env ruby -w\n\n" "#!/usr/local/bin/ruby -w")
 54         ("r" "attr_reader :$${attr_names}" "attr_reader ...")
 55         ("pn" "PStore.new($${file_name})" "PStore.new( ... )")
 56         ("patfh" "File.join(File.dirname(__FILE__), *%w[$${here}])" "path_from_here( ... )")
 57         ("ope" "open($${pipe}) { |$${io}| $. }" "open(\"path/or/url\", \"w\") { |io| ... }")
 58         ("ml" "File.open($${dump}) { |$${file}| Marshal.load($${file}) }" "Marshal.load(obj)")
 59         ("min" "min { |a, b| $. }" "min { |a, b| ... }")
 60         ("max" "max { |a, b| $. }" "max { |a, b| ... }")
 61         ("md" "File.open($${dump}, \"w\") { |$${file}| Marshal.dump($${obj}, $${file}) }" "Marshal.dump(..., file)")
 62         ("lam" "lambda { |$${args}|$. }" "lambda { |args| ... }")
 63         ("gsu" "gsub(/$${pattern}/) { |$${match}|$. }" "gsub(/.../) { |match| ... }")
 64         ("gre" "grep($${pattern}) { |$${match}| $. }" "grep(/pattern/) { |match| ... }")
 65         ("fl" "flunk('$${message}')" "flunk(...)")
 66         ("file" "File.foreach($${file}) { |$${line}| $. }" "File.foreach (\"...\") { |line| ... }")
 67         ("dir" "Dir.glob($${glob}) { |$${file}| $. }" "Dir.glob(\"...\") { |file| ... }")
 68         ("b" "=begin rdoc\n$>$.\n=end" "New Block")
 69         ("begin" "begin\n$>$${paste}\nrescue $${Exception} => $${e}\n$>$.\nend$>\n" "begin ... rescue ... end")
 70         ("bm" "TESTS = $${10_000}\nBenchmark.bmbm($${10}) do |results|\n  $.\nend$>" "Benchmark.bmbm(...) do ... end")
 71         ("am" "alias_method :$${new_name}, :$${old_name}" "alias_method ...")
 72         ("amc" "alias_method_chain :$${first_method}, :$${second_method}" "alias_method_chain ...")) ; general
 73      (1 "definitions" ruby-mode-abbrev-table
 74         ("ts" "require \"test/unit\"\n\nrequire \"tc_$${test_case_file}\"\nrequire \"tc_$${test_case_file}\"\n" "require \"tc_...\" ...")
 75         ("tc" "require \"test/unit\"\n\nrequire \"$${library_file_name}\"\n\nclass Test$${amp} < Test::Unit::TestCase\n$>def test_$${case_name}\n$>$>$.\nend$>\nend$>" "class ... < Test::Unit::TestCase ... end")
 76         ("sin" "class << self; self end" "singleton_class()")
 77         ("rw" "attr_accessor :$${attr_names}" "attr_accessor ...")
 78         ("req" "require \"$.\"" "require \"...\"")
 79         ("modf" "module $${ModuleName}\n$>module ClassMethods\n$>$>$.\nend$>\n$>\n$>extend ClassMethods\n$>\n$>def self.included(receiver)\n$>$>receiver.extend(ClassMethods)\nend$>\n$>\n$>\nend$>" "module ... ClassMethods ... end")
 80         ("mods" "module $${ModuleName}\n$>$.\nend$>" "module ... end")
 81         ("modu" "module $${ModuleName}\n$>module_function\n$>\n$>$.\nend$>" "module ... module_function ... end")
 82         ("mm" "def method_missing(meth, *args, &block)\n$>$.\nend$>" "def method_missing ... end")
 83         ("hash" "Hash.new { |$${hash}, $${key}| $${hash}[$${key}] = $. }" "Hash.new { |hash, key| hash[key] = ... }")
 84         ("forw" "extend Forwardable" "extend Forwardable")
 85         ("enum" "include Enumerable\n\ndef each(&block)\n$>$.\nend$>" "include Enumerable ...")
 86         ("elsif" "elsif $${condition}\n$>$." "elsif ...")
 87         ("doo" "do |$${object}|\n$>$.\nend$>" "Insert do |object| ... end")
 88         ("do" "do\n$>$.\nend$>" "do ... end")
 89         ("defd" "def_delegator :$${del_obj}, :$${del_meth}, :$${new_name}" "def_delegator ...")
 90         ("defds" "def_delegators :$${del_obj}, :$${del_methods}" "def_delegators ...")
 91         ("defs" "def self.$${class_method_name}\n$>$.\nend$>" "def self ... end")
 92         ("deft" "def test_$${case_name}\n$>$.\nend$>" "def test_ ... end")
 93         ("dee" "Marshal.load(Marshal.dump($${obj_to_copy}))" "deep_copy(...)")
 94         ("comp" "include Comparable\n\ndef <=>(other)\n$>$.\nend$>" "include Comparable ...")
 95         ("cladl" "class $${ClassName} < DelegateClass($${ParentClass})\n$>def initialize$${1}\n$>$>super($${del_obj})\n$>$>\n$>$>$.\nend$>\n$>\n$>\nend$>" "class ... < DelegateClass ... initialize ... end")
 96         ("clapr" "class $${ClassName} < $${ParentClass}\n$>def initialize$${1}\n$>$>$.\nend$>\n$>\n$>\nend$>" "class ... < ParentClass ... initialize ... end")
 97         ("clast" "class $${ClassName} < Struct.new(:$${attr_names})\n$>def initialize(*args)\n$>$>super\n$>$>\n$>$>$.\nend$>\n$>\n$>\nend$>" "class ... < Struct ... initialize ... end")
 98         ("class" "class $${ClassName}\n$>$.\nend$>" "class ... end")
 99         ("classi" "class $${ClassName}\n$>def initialize$${1}\n$>$>$.\nend$>\n$>\n$>\nend$>" "class ... initialize ... end")
100         ("clasf" "class << $${self}\n$>$.\nend$>" "class << self ... end")) ; definitions
101      (1 "collections" ruby-mode-abbrev-table
102         ("zip" "zip($${enums}) { |$${row}| $. }" "zip(enums) { |row| ... }")
103         ("sorb" "sort_by { |$${e}| $. }" "sort_by { |e| ... }")
104         ("sor" "sort { |a, b| $. }" "sort { |a, b| ... }")
105         ("select" "select { |$${element}| $${element}.$${2} }$." "select element")
106         ("sel" "select { |$${e}| $. }" "select { |e| ... }")
107         ("reve" "reverse_each { |$${e}| $. }" "reverse_each { |e| ... }")
108         ("reject" "reject { |$${element}| $${element}.$. }" "reject element")
109         ("rej" "reject { |$${e}| $. }" "reject { |e| ... }")
110         ("ran" "sort_by { rand }" "randomize()")
111         ("mapwi" "enum_with_index.map { |$${e}, $${i}| $. }" "map_with_index { |e, i| ... }")
112         ("map" "map { |$${e}| $. }" "map { |e| ... }")
113         ("inject" "inject($${object}) { |$${injection}, $${element}| $${4} }$." "inject object")
114         ("inj" "inject($${init}) { |$${mem}, $${var}| $. }" "inject(init) { |mem, var| ... }")
115         ("flao" "inject(Array.new) { |$${arr}, $${a}| $${arr}.push(*$${a}) }" "flatten_once()")
116         ("fina" "find_all { |$${e}| $. }" "find_all { |e| ... }")
117         ("fin" "find { |$${e}| $. }" "find { |e| ... }")
118         ("fil" "fill($${range}) { |$${i}|$. }" "fill(range) { |i| ... }")
119         ("fet" "fetch($${name}) { |$${key}|$. }" "fetch(name) { |key| ... }")
120         ("eawi" "each_with_index { |$${e}, $${i}| $. }" "each_with_index { |e, i| ... }")
121         ("eai" "each_index { |$${i}| $. }" "each_index { |i| ... }")
122         ("eak" "each_key { |$${key}| $. }" "each_key { |key| ... }")
123         ("eal" "each_line$${1} { |$${line}| $. }" "each_line { |line| ... }")
124         ("eap" "each_pair { |$${name}, $${val}| $. }" "each_pair { |name, val| ... }")
125         ("eas" "each_slice($${2}) { |$${group}| $. }" "each_slice(...) { |group| ... }")
126         ("eav" "each_value { |$${val}| $. }" "each_value { |val| ... }")
127         ("each" "each { |$${element}| $${element}.$. }" "each element")
128         ("eac" "each_cons($${2}) { |$${group}| $. }" "each_cons(...) { |group| ... }")
129         ("eab" "each_byte { |$${byte}| $. }" "each_byte { |byte| ... }")
130         ("ea" "each { |$${e}| $. }" "each { |e| ... }")
131         ("det" "detect { |$${e}| $. }" "detect { |e| ... }")
132         ("deli" "delete_if { |$${e}| $. }" "delete_if { |e| ... }")
133         ("collect" "collect { |$${element}| $${element}.$. }" "collect element")
134         ("col" "collect { |$${e}| $. }" "collect { |e| ... }")
135         ("cl" "classify { |$${e}| $. }" "classify { |e| ... }")
136         ("array" "Array.new($${10}) { |$${i}|$. }" "Array.new(10) { |i| ... }")
137         ("any" "any? { |$${e}| $. }" "any? { |e| ... }")
138         ("all" "all? { |$${e}| $. }" "all? { |e| ... }")) ; collections
139      (0 "erb" html-mode-abbrev-table html-helper-mode-abbrev-table nxml-mode-abbrev-table
140         ("title" "<title>$${title}</title>" "title")
141         ("textarea" "<textarea name=\"$${Name}\" rows=\"$${8}\" cols=\"$${40}\">$.</textarea>" "textarea")
142         ("table" "<table border=\"$${0}\" $${cellpadding}>\n$><tr><th>$${Header}</th></tr>\n$><tr><td>$${Data}</td></tr>\n</table>" "table")
143         ("style" "<style type=\"text/css\" media=\"screen\">\n$>$.\n</style>" "style")
144         ("scriptsrc" "<script src=\"$${1}\" type=\"text/javascript\" charset=\"$${utf}\"></script>" "script with source")
145         ("script" "<script type=\"text/javascript\" charset=\"utf-8\">\n$>$.\n</script>" "script")
146         ("movie" "<object width=\"$${2}\" height=\"$${3}\" classid=\"clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B\" codebase=\"http://www.apple.com/qtactivex/qtplugin.cab\">\n$><param name=\"src\" value=\"$${1}\"/>\n$><param name=\"controller\" value=\"$${4}\"/>\n$><param name=\"autoplay\" value=\"$${5}\"/>\n$><embed src=\"$${movie}\"\n$>$>width=\"$${320}\" height=\"$${240}\"\n$>$>controller=\"$${true}\" autoplay=\"$${true}\"\n$>$>scale=\"tofit\" cache=\"true\"\n$>$>pluginspage=\"http://www.apple.com/quicktime/download/\"\n$>/>\n</object>" "quicktime")
147         ("meta" "<meta name=\"$${name}\" content=\"$${content}\"/>" "meta")
148         ("mailto" "<a href=\"mailto:$${example}?subject=$${feedback}\">$${email}</a>" "mailto")
149         ("link" "<link rel=\"$${stylesheet}\" href=\"$${master}\" type=\"text/css\" media=\"$${screen}\" title=\"$${title}\" charset=\"$${utf}\"/>" "link")
150         ("licai" "<%= link_to \"$${text}\", :controller => \"$${items}\", :action => \"$${edit}\", :id => $${item} %>" "link_to (controller, action, id)")
151         ("lica" "<%= link_to \"$${text}\", :controller => \"$${items}\", :action => \"$${index}\" %>" "link_to (controller, action)")
152         ("lica" "<%= link_to \"$${text}\", :controller => \"$${items}\", :action => \"$${index}\" %>" "link_to (controller, action)")
153         ("liai" "<%= link_to \"$${text}\", :action => \"$${edit}\", :id => $${item} %>" "link_to (action, id)")
154         ("lic" "<%= link_to \"$${text}\", :controller => \"$${items}\" %>" "link_to (controller)")
155         ("lia" "<%= link_to \"$${text}\", :action => \"$${index}\" %>" "link_to (action)")
156         ("input" "<input type=\"$${button}\" name=\"$${some_name}\" value=\"$${3}\"$${id}>" "input")
157         ("head" "<head>\n$><meta http-equiv=\"Content-type\" content=\"text/html; charset=utf-8\"/>\n$><title>$${title}</title>\n$>$.\n</head>" "head")
158         ("h" "<h1 id=\"$${alpha}\">$${paste}</h1>" "heading")
159         ("ft" "<%= form_tag :action => \"$${update}\" %>\n$.\n<%= end_form_tag %>" "form_tag")
160         ("ff" "<%= form_for :$${item}, :action => \"$${update}\" %>\n$.\n<% end %>" "form_for")
161         ("form" "<form action=\"$${action}\" method=\"$${post}\" accept-charset=\"utf-8\">\n$>$.\n\n$><p><input type=\"submit\" value=\"Continue &rarr;\"/></p>\n</form>" "form")
162         ("dtht" "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\n$>\"http://www.w3.org/TR/html4/strict.dtd\">\n" "HTML -- 4.01 Strict")
163         ("dchttr" "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\n$>\"http://www.w3.org/TR/html4/loose.dtd\">\n" "HTML -- 4.01 Transitional")
164         ("dcxmlf" "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Frameset//EN\"\n$>\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd\">\n" "XHTML -- 1.0 Frameset")
165         ("dcxmls" "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n$>\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n" "XHTML -- 1.0 Strict")
166         ("dcxmlt" "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n$>\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" "XHTML -- 1.0 Transitional")
167         ("dcxml1" "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"\n$>\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n" "XHTML -- 1.1")
168         ("body" "<body id=\"$${id}\" $${onload}>\n$>$.\n</body>" "body")
169         ("div" "<div>\n$>$${paste}\n</div>" "div")
170         ("%h" "<%=h $${@item} %>" "<% h ... %>")
171         ("%if" "<% if $${cond} -%>\n$.\n<% end -%>" "<% if/end %>")
172         ("%ifel" "<% if $${cond} -%>\n$.\n<% else -%>\n<% end -%>" "<% if/else/end %>")
173         ("%unless" "<% unless $${cond} -%>\n$.\n<% end -%>" "<% unless/end %>")
174         ("%for" "<% for $${elem} in @$${list} %>\n$>$.\n<% end %>$>" "<% for/end %>")
175         ("%" "<% $. -%>" "<% ... %>")
176         ("%%" "<%= $. %>" "<%= ... %>")) ; erb
177      (0 "controller" rails-controller-minor-mode-abbrev-table
178         ("ru"  "render :update do |page|\n$>$.\nend$>" "render :update ...")
179         ("bf"  "before_filter :$${filter}" "refore_filter")
180         ("af"  "after_filter :$${filter}" "after_filter")
181         ("arf"  "around_filter :$${filter}" "around_filter")) ; controller
182      (0 "RESTful" rails-controller-minor-mode-abbrev-table
183         rails-view-minor-mode-abbrev-table
184         rails-helper-minor-mode-abbrev-table
185         rails-functional-test-minor-mode-abbrev-table
186         ("rest" "respond_to do |format|\n$>format.html$>$.\nend$>" "respond_to ..." rails-controller-minor-mode-abbrev-table)
187         ("rindex" "$${,rails-snippets-feature:rest-index}" "models_url")
188         ("rshow" "$${,rails-snippets-feature:rest-show}" "model_url(@model)")
189         ("rnew" "$${,rails-snippets-feature:rest-new}" "new_model_url")
190         ("redit" "$${,rails-snippets-feature:rest-edit}" "edit_model_url(@model)")
191         ("rcreate" "$${,rails-snippets-feature:rest-create}" "models_url")
192         ("rupdate" "$${,rails-snippets-feature:rest-update}" "model_url(@model)")
193         ("rdestroy" "$${,rails-snippets-feature:rest-destroy}" "model_url(@model)")) ; RESTFul
194      (0 "render" rails-controller-minor-mode-abbrev-table
195         rails-view-minor-mode-abbrev-table
196         rails-helper-minor-mode-abbrev-table
197         ("rps" "render :partial => '$${item}', :status => $${500}" "render (partial, status)")
198         ("rt" "render :text => '$${render}'" "render (text)")
199         ("rtl" "render :text => '$${render}', :layout => '$${layoutname}'" "render (text, layout)")
200         ("rtlt" "render :text => '$${render}', :layout => $${true}" "render (text, layout => true)")
201         ("rts" "render :text => '$${render}', :status => $${401}" "render (text, status)")
202         ("rf" "render :file => '$${filepath}'" "render (file)")
203         ("rfu" "render :file => '$${filepath}', :use_full_path => $${false}" "render (file, use_full_path)")
204         ("ri" "render :inline => '$${hello}'" "render (inline)")
205         ("ril" "render :inline => '$${hello}', :locals => { $${name} => '$${value}'$${4} }" "render (inline, locals)")
206         ("rit" "render :inline => '$${hello}', :type => $${rxml}" "render (inline, type)")
207         ("rl" "render :layout => '$${layoutname}'" "render (layout)")
208         ("rn" "render :nothing => $${true}" "render (nothing)")
209         ("rns" "render :nothing => $${true}, :status => $${401}" "render (nothing, status)")
210         ("rp" "render :partial => '$${item}'" "render (partial)")
211         ("rpc" "render :partial => '$${item}', :collection => $${items}" "render (partial, collection)")
212         ("rpl" "render :partial => '$${item}', :locals => { :$${name} => '$${value}'$${4} }" "render (partial, locals)")
213         ("rpo" "render :partial => '$${item}', :object => $${object}" "render (partial, object)")
214         ("rcea" "render_component :action => '$${index}'" "render_component (action)")
215         ("rcec" "render_component :controller => '$${items}'" "render_component (controller)")
216         ("rceca" "render_component :controller => '$${items}', :action => '$${index}'" "render_component (controller, action)")
217         ("ra" "render :action => '$${index}'" "render (action)")
218         ("ral" "render :action => '$${index}', :layout => '{default}'" "render (action, layout)")) ; render
219      (0 "redirect_to" rails-controller-minor-mode-abbrev-table
220         rails-view-minor-mode-abbrev-table
221         rails-helper-minor-mode-abbrev-table
222         ("rea" "redirect_to :action => '$${index}'" "redirect_to (action)")
223         ("reai" "redirect_to :action => '$${show}', :id => $${item}" "redirect_to (action, id)")
224         ("rec" "redirect_to :controller => '$${items}'" "redirect_to (controller)")
225         ("reca" "redirect_to :controller => '$${items}', :action => '$${list}'" "redirect_to (controller, action)")
226         ("recai" "redirect_to :controller => '$${items}', :action => '$${show}', :id => $${item}" "redirect_to (controller, action, id)")) ; redirecto_to
227      (0 "rails" ruby-mode-abbrev-table
228         ("rdl" "RAILS_DEFAULT_LOGGER.debug '$${message}'$." "RAILS_DEFAULT_LOGGER.debug")
229         ("nr" "@$${item}.new_record?" "item.new_record?")) ; rails
230      (0 "model" rails-model-minor-mode-abbrev-table
231         ("va" "validates_associated :$${attribute}" "validates_associated")
232         ("vc" "validates_confirmation_of :$${attribute}" "validates_confirmation_of")
233         ("ve" "validates_exclusion_of :$${attribute}" "validates_exclusion_of")
234         ("vu" "validates_uniqueness_of :$${attribute}" "validates_uniqueness_of")
235         ("vpif" "validates_presence_of :$${attribute}, :if => proc { |obj| $${condition} }" "validates_presence_of if")
236         ("vp" "validates_presence_of :$${attribute}" "validates_presence_of")
237         ("vl" "validates_length_of :$${attribute}, :within => $${20}" "validates_length_of")
238         ("bt" "belongs_to :$${model}" "belongs_to")
239         ("hm" "has_many :$${objects}" "has_many")
240         ("hmt" "has_many :$${objects}, :through => :$${,rails-snippets-feature:prev-has-many-table-name}" "has_many :through")
241         ("ho" "has_one :$${object}" "has_one")
242         ("habtm" "has_and_belongs_to_many :$${object}" "has_and_belongs_to_many")) ; model
243      (0 "migrations" rails-migration-minor-mode-abbrev-table
244         ("tcls" "t.column :$${title}, :$${string}\n$>tcls$." "create several columns")
245         ("tcl" "t.column :$${title}, :$${string}$." "create column")
246         ("tcln" "t.column :$${title}, :$${string}, :null => false$." "create column :null => false")
247         ("acl" "add_column :$${,rails-snippets-feature:migration-table-name}, :$${column}, :$${string}" "add column")
248         ("ai" "add_index :$${,rails-snippets-feature:migration-table-name}, $${column}" "add index")
249         ("aiu" "add_index :$${,rails-snippets-feature:migration-table-name}, $${column}, :unique => true" "add unique index")
250         ("rmcl" "remove_column :$${,rails-snippets-feature:migration-table-name}, :$${column}" "remove column")
251         ("recl" "rename_column :$${column}, :$${new_column}" "rename column")
252         ("dt" "drop_table :$${,rails-snippets-feature:migration-table-name}$." "drop table")
253         ("ct" "create_table :$${,rails-snippets-feature:migration-table-name} do |t|\n$>tcls$.\nend$>" "create_table")
254         ("ret" "rename_table :$${,rails-snippets-feature:migration-table-name}, :$${new_name}$." "rename table")) ; migrations
255      (0 "environment" ruby-mode-abbrev-table
256         ("logd" "logger.debug '$${message}'$." "logger.debug")
257         ("loge" "logger.error '$${message}'$." "logger.error")
258         ("logf" "logger.fatal '$${message}'$." "logger.fatal")
259         ("logi" "logger.info '$${message}'$." "logger.info")
260         ("logw" "logger.warn '$${message}'$." "logger.warn")
261         ("par" "params[:$${id}]" "params[...]")
262         ("session" "session[:$${User}]" "session[...]")
263         ("flash" "flash[:$${notice}] = '$${Successfully}'$." "flash[...]")) ; environment
264      (0 "tests" rails-functional-test-minor-mode-abbrev-table rails-unit-test-minor-mode-abbrev-table
265         ("fix" "$${,rails-snippets-feature:fixture}(:$${one})$." "models(:name)")) ; functional tests
266      (0 "assertions" rails-functional-test-minor-mode-abbrev-table rails-unit-test-minor-mode-abbrev-table
267         ("art" "assert_redirected_to :action => '$${index}'" "assert_redirected_to")
268         ("as" "assert $${test}" "assert(...)")
269         ("asa" "assert assigns(:$${,rails-snippets-feature:model-name})" "assert assigns(...)")
270         ("ase" "assert_equal $${expected}, $${actual}" "assert_equal(...)")
271         ("asid" "assert_in_delta $${expected_float}, $${actual_float}, $${20}" "assert_in_delta(...)")
272         ("asio" "assert_instance_of $${ExpectedClass}, $${actual_instance}" "assert_instance_of(...)")
273         ("asko" "assert_kind_of $${ExpectedKind}, $${actual_instance}" "assert_kind_of(...)")
274         ("asm" "assert_match(/$${expected_pattern}/, $${actual_string})" "assert_match(...)")
275         ("asn" "assert_nil $${instance}" "assert_nil(...)")
276         ("asne" "assert_not_equal $${unexpected}, $${actual}" "assert_not_equal(...)")
277         ("asnm" "assert_no_match(/$${unexpected_pattern}/, $${actual_string})" "assert_no_match(...)")
278         ("asnn" "assert_not_nil $${instance}" "assert_not_nil(...)")
279         ("asnr" "assert_nothing_raised $${Exception}  { $. }" "assert_nothing_raised(...) { ... }")
280         ("asns" "assert_not_same $${unexpected}, $${actual}" "assert_not_same(...)")
281         ("asnt" "assert_nothing_thrown { $. }" "assert_nothing_thrown { ... }")
282         ("aso" "assert_operator $${left}, :$${operator}, $${right}" "assert_operator(...)")
283         ("asr" "assert_raise $${Exception} { $. }" "assert_raise(...) { ... }")
284         ("asre" "assert_response :$${success}" "assert_response")
285         ("asrt" "assert_respond_to $${object}, :$${method}" "assert_respond_to(...)")
286         ("ass" "assert_same $${expected}, $${actual}" "assert_same(...)")
287         ("assd" "assert_send [$${object}, :$${message}, $${args}]" "assert_send(...)")
288         ("ast" "assert_throws :$${expected} { $. }" "assert_throws(...) { ... }")
289         ("astm" "assert_template '$${index}'" "assert_template"))))
290  
291  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
292  ;;
293  ;; Snippets functions
294  ;;
295  
296  (defmacro rails-snippets-feature:create-lambda (str)
297    `(lambda () (interactive) (snippet-insert ,(symbol-value str))))
298  
299  (defun rails-snippets-feature:create-keymap ()
300    (let ((keymap (make-sparse-keymap "Snippets"))
301          ret level stack)
302      (dolist (line rails-snippets-feature:list)
303        (let ((cur-level (nth 0 line))  ; current the menu livel
304              (menu-item (nth 1 line))  ; current the menu item name
305              (line (cddr line))        ; skip level and menu name
306              (abbrev-tables))
307          ;; fill stack
308          (cond
309           ((not level)
310            (setq level cur-level)
311            (setq stack (list menu-item)))
312           ((= cur-level level)
313            (setq stack (append (reverse (cdr (reverse stack))) (list menu-item))))
314           ((> cur-level level)
315            (setq level cur-level)
316            (setq stack (append stack (list menu-item))))
317           ((< cur-level level)
318            (setq stack (append (reverse (nthcdr (+ 1 (- level cur-level)) (reverse stack)))
319                                (list menu-item)))))
320          (let ((cur-keymap (vconcat (mapcar #'make-symbol stack))))
321            ;; make a menu entry for group of snippets
322            (define-key keymap cur-keymap
323              (cons menu-item (make-sparse-keymap menu-item)))
324            ;; scan abbrev tables
325            (while (not (listp (car line)))
326              (setq abbrev-tables (append abbrev-tables (list (car line))))
327              (setq line (cdr line)))
328            (when abbrev-tables
329              ;; sort and scan snippets
330              (dolist (snip-line (sort line (lambda(x y) (not (string< (car x)(car y))))))
331                (let* ((abbr (nth 0 snip-line))
332                       (snip (nth 1 snip-line))
333                       (desc (nth 2 snip-line))
334                       (loc-abbrev-table (nth 3 snip-line))
335                       (abbrev-tables (if loc-abbrev-table
336                                          (list loc-abbrev-table)
337                                        abbrev-tables))
338                       (compiled-snip (rails-snippets-feature:create-lambda snip)))
339                  ;; create a menu entry for a snippet
340                  (define-key keymap (vconcat cur-keymap (list (make-symbol abbr)))
341                    (cons (format "%s \t%s" abbr desc) compiled-snip))
342                  ;; create abbrevs for a snippet
343                  (dolist (table abbrev-tables)
344                    (unless (boundp table)
345                      (define-abbrev-table table ()))
346                    (define-abbrev (symbol-value table) abbr "" compiled-snip))))))))
347      keymap))
348  
349  (defadvice snippet-insert (before snippet-insert-before-advice first (template) activate)
350    (let ((pos 0))
351      (while (setq pos (string-match (snippet-field-regexp) template pos))
352        (let ((match (match-string 2 template))
353              (beg (match-beginning 2))
354              (end (match-end 2))
355              (repl))
356          (setq pos end)
357          (when (= 44 (car (string-to-list match))) ;; 44 - [,]
358            (save-match-data
359              (setq repl (apply (intern (substring match 1)) (list)))))
360          (when repl
361            (setq template
362                  (concat (substring template 0 beg)
363                          repl
364                          (substring template end (length template))))
365            (setq pos (- pos
366                         (- (length match) (length repl)))))))))
367  
368  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
369  ;;
370  ;; Functions for dynamic snippets
371  ;;
372  
373  (defun rails-snippets-feature:migration-table-name ()
374    (let (str)
375      (string=~ "[0-9]+_create_\\([^\\.]+\\)\\.rb$" (buffer-name)
376                (setq str $1))
377      (if str str "table")))
378  
379  (defun rails-snippets-feature:prev-has-many-table-name ()
380    (save-excursion
381      (if (search-backward-regexp "has_many :\\(\\w+\\)" nil t)
382          (match-string-no-properties 1)
383        "table")))
384  
385  (defun rails-snippets-feature:fixture ()
386    (let ((controller (rails-core:current-controller))
387          (model (rails-core:current-model)))
388      (cond
389       (controller (downcase controller))
390       (model (pluralize-string (downcase model)))
391       (t "fixture"))))
392  
393  (defun rails-snippets-feature:model-name ()
394    (let ((controller (rails-core:current-controller)))
395      (if controller
396          (singularize-string (downcase controller))
397        "model")))
398  
399  (defun rails-snippets-feature:rest (action)
400    (when-bind
401     (controller (rails-core:current-controller))
402     (let* ((plural (downcase (pluralize-string controller)))
403            (singular (downcase (singularize-string controller)))
404            (model (concat "@" singular)))
405       (case action
406         (:index
407          (tooltip-show (format "GET /%s" plural))
408          (format "%s_url" plural))
409         (:show
410          (tooltip-show (format "GET /%s/1" plural))
411          (format "%s_url(%s)" singular model))
412         (:new
413          (tooltip-show (format "GET /%s/new" plural))
414          (format "new_%s_url" singular))
415         (:edit
416          (tooltip-show (format "GET /%s/1;edit" plural))
417          (format "edit_%s_url(%s)" singular model))
418         (:create
419          (tooltip-show (format "POST /%s" plural))
420          (format "%s_url" plural))
421         (:update
422          (tooltip-show (format "PUT /%s/1" plural))
423          (format "%s_url(%s)" singular model))
424         (:destroy
425          (tooltip-show (format "DELETE /%s/1" plural))
426          (format "%s_url(%s)" singular model))))))
427  
428  (defun rails-snippets-feature:rest-index ()
429    (rails-snippets-feature:rest :index))
430  
431  (defun rails-snippets-feature:rest-show ()
432    (rails-snippets-feature:rest :show))
433  
434  (defun rails-snippets-feature:rest-new ()
435    (rails-snippets-feature:rest :new))
436  
437  (defun rails-snippets-feature:rest-edit ()
438    (rails-snippets-feature:rest :edit))
439  
440  (defun rails-snippets-feature:rest-create ()
441    (rails-snippets-feature:rest :create))
442  
443  (defun rails-snippets-feature:rest-update ()
444    (rails-snippets-feature:rest :update))
445  
446  (defun rails-snippets-feature:rest-destroy ()
447    (rails-snippets-feature:rest :destroy))
448  
449  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
450  ;;
451  ;; Install function
452  ;;
453  
454  (defun rails-snippets-feature:install ()
455    (define-key rails-minor-mode-map
456      [menu-bar rails-snippets]
457      (cons "Snippets" (rails-snippets-feature:create-keymap))))
458  
459  (provide 'rails-snippets-feature)