casey_jones 0.0.99

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/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ gem 'rails', '3.0.0.beta4'
2
+ gem 'sqlite3-ruby', :require => 'sqlite3'
3
+ gem 'jeweler'
4
+ gem "da_huangs_ruby_extensions"
5
+
data/README ADDED
@@ -0,0 +1,59 @@
1
+ == HABTM Example
2
+
3
+ Complex forms on a HABTM association.
4
+
5
+ Using code borrowed from Pat (http://patshaughnessy.net), whose view_mapper
6
+ finally taught this hobbyist hacker to write forms.
7
+
8
+ Hopefully this will fit snugly into someone else's gem
9
+
10
+ == Installation
11
+
12
+ * Install as a gem:
13
+ # Add to your Gemfile
14
+ gem "anaf_habtm"
15
+ * or as a plugin
16
+ rails plugin install git://github.com/tylergannon/anaf_habtm.git
17
+
18
+ Run the generator to place the javascript in the right place:
19
+
20
+ rails generate anaf_habtm
21
+
22
+ Add the following to your layout:
23
+ <%= javascript_include_tag 'nested_attributes.js' %>
24
+
25
+ == Usage
26
+
27
+ Inside your model, call anaf_habtm just as you would call has_and_belongs_to_many,
28
+ except now you need to offer a code block telling rails what to do with each object.
29
+ The plugin will handle deleting stuff.
30
+
31
+ # Basically, your code block needs to return an object of the correct
32
+ # type for your association collection, or else nil if your code
33
+ # determines that the object should be rejected.
34
+ class Customer < ActiveRecord::Base
35
+ anaf_habtm :orders, :autosave => true, :uniq => false do |params, order|
36
+ order = order ||= Order.new
37
+ order.attributes = params
38
+ logger.error params.inspect
39
+ order
40
+ end
41
+ end
42
+
43
+ class Order < ActiveRecord::Base
44
+ has_and_belongs_to_many :customers
45
+ anaf_habtm :items, :autosave => true, :uniq => false do |params, item|
46
+ logger.error "ITEM::: #{params.inspect}"
47
+ item ||= Item.find_or_create_by_name(params["name"])
48
+ end
49
+ end
50
+
51
+ == Additional info
52
+
53
+ See the example app at http://github.com/tylergannon/accepts-nested-attributes-habtm-example for more details.
54
+
55
+ Also check out Pat's view_mapper... it can generate the code you need inside your views.
56
+
57
+ http://github.com/patshaughnessy/view_mapper
58
+
59
+
data/Rakefile ADDED
@@ -0,0 +1,70 @@
1
+
2
+ PKG_FILES = FileList[
3
+ 'anaf_habtm.gemspec',
4
+ 'Gemfile',
5
+ 'install.rb',
6
+ 'Rakefile', 'README', 'uninstall.rb',
7
+ 'assets/**/*',
8
+ 'lib/**/*',
9
+ 'rails/**/*',
10
+ 'test/**/*'
11
+ ]
12
+
13
+ require 'rubygems'
14
+ require 'rake'
15
+
16
+ begin
17
+ require 'jeweler'
18
+ Jeweler::Tasks.new do |s|
19
+ s.name = "casey_jones"
20
+ s.author = "Tyler Gannon"
21
+ s.email = "t--g__a--nnon@gmail.com"
22
+ s.homepage = "http://github.com/tylergannon/anaf_habtm"
23
+ s.platform = Gem::Platform::RUBY
24
+ s.description = "some extra stuff for rails apps"
25
+ s.summary = "My favorite rails goodies all in one"
26
+ s.files = PKG_FILES.to_a
27
+ s.require_path = "lib"
28
+ s.has_rdoc = false
29
+ s.extra_rdoc_files = ["README"]
30
+ end
31
+
32
+ Jeweler::GemcutterTasks.new
33
+ rescue LoadError
34
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
35
+ end
36
+
37
+ require 'rake/testtask'
38
+ Rake::TestTask.new(:test) do |test|
39
+ test.libs << 'lib' << 'test'
40
+ test.pattern = 'test/**/test_*.rb'
41
+ test.verbose = true
42
+ end
43
+
44
+ begin
45
+ require 'rcov/rcovtask'
46
+ Rcov::RcovTask.new do |test|
47
+ test.libs << 'test'
48
+ test.pattern = 'test/**/test_*.rb'
49
+ test.verbose = true
50
+ end
51
+ rescue LoadError
52
+ task :rcov do
53
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
54
+ end
55
+ end
56
+
57
+ task :test => :check_dependencies
58
+
59
+ task :default => :test
60
+
61
+ require 'rake/rdoctask'
62
+ Rake::RDocTask.new do |rdoc|
63
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
64
+
65
+ rdoc.rdoc_dir = 'rdoc'
66
+ rdoc.title = "da_huangs_ruby_extensions #{version}"
67
+ rdoc.rdoc_files.include('README*')
68
+ rdoc.rdoc_files.include('lib/**/*.rb')
69
+ end
70
+
data/install.rb ADDED
@@ -0,0 +1 @@
1
+ # Install hook code here
@@ -0,0 +1,34 @@
1
+ module ActsAsLinkable
2
+ module ActiveRecordExtensions
3
+ def acts_as_linkable(opts={}, &block)
4
+ class_eval "def link_attr; #{opts.inspect}; end;"
5
+ end
6
+ end
7
+
8
+ module ActionViewExtensions
9
+ def link(obj)
10
+ raise "I can't link to nil." unless obj
11
+ if (obj.class == Array) || (obj.class == ActiveRecord::Relation)
12
+ obj.map{|v| link(v)}.to_sentence
13
+ else
14
+ p = obj.link_attr
15
+ p[:partial] = "#{obj.class.name.tableize}/link" if p.empty?
16
+ unless p[:partial].nil?
17
+ obj_name = (p[:object_name] ||= obj.class.name.underscore).to_s.to_sym
18
+ (render :partial => p[:partial], :locals => {obj_name => obj}).strip
19
+ else
20
+ opts = {}
21
+ link_attr = obj.link_attr
22
+ link_attr.each do |key, val|
23
+ link_attr[key] = obj.send(val) if val.class == Symbol
24
+ end
25
+ opts[:title] = link_attr[:title] if link_attr.has_key?(:title)
26
+ link_to link_attr[:name], obj, opts
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ ActiveRecord::Base.extend(ActsAsLinkable::ActiveRecordExtensions)
33
+ ActionView::Base.send :include, ActsAsLinkable::ActionViewExtensions
34
+
@@ -0,0 +1,2 @@
1
+ require 'ajax_loading/controller_resource'
2
+
@@ -0,0 +1,37 @@
1
+ module AjaxLoading
2
+ class ControllerResource < CanCan::ControllerResource
3
+ def initialize(controller, name, parent = nil, options = {})
4
+ super(controller, name, parent, options)
5
+ end
6
+
7
+ def load_resource
8
+ puts "AjaxLoading::load_resource"
9
+ params = @controller.params
10
+ if params.has_key?(:associated)
11
+ ass_params = params[:associated]
12
+ relation = ass_params["class_name"].constantize.find(ass_params["id"])
13
+ association = ass_params["association"]
14
+ instance_variable_set 'container',
15
+ ass_params["container"] ||= relation.element_id(:show, association)
16
+
17
+ self.model_instance = relation.send(association)
18
+ elsif collection_action?
19
+ self.model_instance = model_class.where('1=1')
20
+ else
21
+ super
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def instance_variable_set(name, value)
28
+ name = '@'+name unless name.include?('@')
29
+ @controller.instance_variable_set(name, value)
30
+ end
31
+ def instance_variable_get(name)
32
+ name = '@'+name unless name.include?('@')
33
+ @controller.instance_variable_get(name)
34
+ end
35
+ end
36
+ end
37
+
@@ -0,0 +1,45 @@
1
+
2
+ module AnafHabtm
3
+ module ActiveRecord
4
+ def anaf_habtm(association, options={}, &block)
5
+ class_eval do
6
+ # Define a proc that will look up the (potentially) existing object
7
+ finder = proc {|id| association.to_s.singularize.camelize.constantize.where(:id=>id).first
8
+ }
9
+
10
+ # Define a proc that will set the association collection
11
+ set_collection = proc {|me, coll| me.send("#{association.to_s.tableize}=", coll)}
12
+ has_and_belongs_to_many association.to_sym, options
13
+ # Define the actual association setter.
14
+ define_method "#{association.to_s.tableize}_attributes=", lambda{|attributes_for_association|
15
+ coll = []
16
+
17
+ attributes_for_association.each_value do |params|
18
+ next if params["_destroy"] == "1"
19
+ obj = finder.call(params["id"]) if params.has_key?("id")
20
+ params.extend(AnafHabtm::HashExtension)
21
+ # ActiveRecord::Base.attributes=() doesn't like extra parameters.
22
+ coll << block.call(params.copy_without_destroy, obj)
23
+ end
24
+ set_collection.call(self, coll)
25
+ }
26
+ end
27
+ end
28
+
29
+ def named_association(member, attribute, opts={})
30
+ member = member.to_s
31
+ klass = opts.has_key?(:class) ? opts[:class_name] : member.to_s.singularize.camelize
32
+ attribute = attribute.to_s
33
+ if opts.has_key?(:create)
34
+ class_eval "def #{member}_#{attribute}=(#{attribute});
35
+ return if #{attribute}.blank?
36
+ self.#{member} = #{klass}.find_or_create_by_#{attribute}(#{attribute})
37
+ end;"
38
+ else
39
+ class_eval "def #{member}_#{attribute}=(#{attribute}); self.#{member} = #{klass}.find_by_#{attribute}(#{attribute}) unless #{attribute}.blank?; end;"
40
+ end
41
+ class_eval "def #{member}_#{attribute}; #{member}.#{attribute} if #{member}; end;"
42
+ end
43
+ end
44
+ end
45
+
@@ -0,0 +1,8 @@
1
+ require 'casey_jones/active_record_extensions'
2
+ require 'casey_jones/application_helper_methods'
3
+ require 'casey_jones/string_reader'
4
+ require 'ajax_loading/ajax_loading'
5
+ require 'acts_as_linkable/acts_as_linkable'
6
+ ActiveRecord::Base.extend(CaseyJones::ActiveRecord)
7
+ ActionView::Base.send :include, CaseyJones::ApplicationHelperMethods
8
+
@@ -0,0 +1,160 @@
1
+
2
+ module CaseyJones
3
+ module ActiveRecord
4
+ def autocomplete_format(&block)
5
+ class_eval do
6
+ @autocomplete_block = block
7
+ def self.to_autocomplete(items)
8
+ items.map{|t| @autocomplete_block.call(t)}.to_json
9
+ end
10
+ end
11
+ end
12
+
13
+ # Needs to call scopes on a class and pass it values that are
14
+ # pulled from a hash called obj_attr
15
+ def make_scope_string(find_opts)
16
+ _scopes = []
17
+ find_opts.each{ |scope, attr_name|
18
+ if attr_name.class == Hash
19
+ _scopes << "#{scope.to_s}(obj_attr[#{name.first[0].to_s}][#{name.first[1].to_s}])"
20
+ else
21
+ _scopes << "#{scope.to_s}(obj_attr[#{name.to_s}])"
22
+ end
23
+ }
24
+ _scopes.join(".")
25
+ end
26
+
27
+ def anaf_habtm(association, options={})
28
+ ar_opts = options[:ar_options] ||= {}
29
+ klass = ar_opts[:class_name] ||= association.to_s.singularize.camelize
30
+ class_eval do
31
+ has_and_belongs_to_many association.to_sym, ar_opts
32
+ end
33
+ find_line = "obj = obj ||= #{klass}.#{make_scope_string(options[:find])}.first" if options.has_key?(:find)
34
+ association = association.to_s.underscore.tableize
35
+ scope_string =
36
+ class_eval <<END
37
+ def #{association}_attributes=(attr_hash)
38
+ obj_coll = []
39
+ attr_hash.each_value do |obj_attr|
40
+ next if obj_attr["_destroy"] == "1"
41
+ obj = #{klass}.find(obj_attr["id"]) if obj_attr.has_key?("id")
42
+ obj_attr = obj_attr.reject_keys ["id", "_destroy"]
43
+ #{find_line}
44
+ if obj && obj.update_attributes(obj_attr)
45
+ obj_coll << obj
46
+ elsif (obj = #{klass}.new(obj_attributes)) && obj.save
47
+ obj_coll << obj
48
+ end
49
+ end
50
+ self.#{association} = obj_coll
51
+ end
52
+ END
53
+ end
54
+
55
+ def association_text(association, opts={})
56
+ raise "Must give a name for text_association" unless opts.has_key?(:name)
57
+ class_eval do
58
+ if opts.has_key?(:class_name)
59
+ klass = opts[:class_name].constantize
60
+ else
61
+ klass = association.to_s.singularize.camelize.constantize
62
+ end
63
+ define_method "#{association.to_s}_text=", lambda{ |text|
64
+ return if text.empty?
65
+ coll = StringReader.new.read_items(text) do |name, commentary|
66
+ a = klass.undecorate(name) if klass.methods.include?("undecorate")
67
+ if opts.has_key?(:scope)
68
+ obj = self.send(association).scopes[opts[:scope]].call(name).first
69
+ end
70
+ params = {opts[:name]=>name}
71
+ params[opts[:commentary]] = commentary if opts.has_key?(:commentary)
72
+ obj = obj ||= klass.new
73
+ obj = klass.find(obj) unless obj.new_record?
74
+ obj.decoration = a if a
75
+ obj.attributes = params
76
+ obj.save
77
+ obj
78
+ end
79
+ self.send("#{association.to_s}=", coll)
80
+ }
81
+
82
+ define_method "#{association.to_s}_text", lambda{
83
+ StringReader.new.write_items(self.send(association.to_s)) do |item|
84
+ name = item.send(opts[:name])
85
+ name = item.decorate(name) if item.methods.include?("decorate")
86
+ [name, opts.has_key?(:commentary) ? item.send(opts[:commentary]) : ""]
87
+ end
88
+ }
89
+ end
90
+ end
91
+
92
+ def named_association(member, attribute, opts={})
93
+ member = member.to_s
94
+ klass = (opts.has_key?(:class_name) ? opts[:class_name] : member.to_s.singularize.camelize).constantize
95
+ attribute = attribute.to_s
96
+ if opts.has_key?(:create)
97
+ class_eval do
98
+ define_method "#{member}_#{attribute}=", lambda{|value|
99
+ return if value.blank?
100
+ obj = klass.named(value)
101
+ obj = obj ||= klass.create(attribute => value)
102
+ self.send("#{member}=", obj)
103
+ }
104
+ end
105
+ else
106
+ class_eval do
107
+ define_method "#{member}_#{attribute}=", lambda{|value|
108
+ self.send("#{member}=",klass.named(value)) unless value.blank?
109
+ }
110
+ end
111
+ end
112
+ class_eval "def #{member}_#{attribute};
113
+ #{member}.#{attribute} if #{member};
114
+ end;"
115
+ end
116
+
117
+ def search_on(*cols)
118
+ class_eval "def self.search_columns; #{cols.map{|t| t.to_s}.to_ary.inspect}; end;"
119
+ class_eval do
120
+ scope :search, lambda{|str|
121
+ items = like_condition(str.downcase)
122
+ if scopes.has_key?(:search_mod)
123
+ items = items.search_mod
124
+ end
125
+ items
126
+ }
127
+ scope :with_name, lambda{|str|
128
+ equals_condition(str.downcase).limit(1)
129
+ }
130
+ end
131
+ end
132
+
133
+ def lookup(params)
134
+ str = params[:id]
135
+ if str.match(/\D/)
136
+ named(str)
137
+ else
138
+ find(str)
139
+ end
140
+ end
141
+
142
+ def like_condition(str)
143
+ where(condition("ilike '%#{str}%'"))
144
+ end
145
+
146
+ def equals_condition(str)
147
+ where(condition("= '#{str.downcase}'"))
148
+ end
149
+
150
+
151
+ def named(str)
152
+ with_name(str).first
153
+ end
154
+
155
+ def condition(cond)
156
+ search_columns.map{|c| "trim(lower(#{c})) #{cond}"}.join(" or ")
157
+ end
158
+ end
159
+ end
160
+
@@ -0,0 +1,39 @@
1
+ module CaseyJones
2
+ module ApplicationHelperMethods
3
+ def remove_child_link(name, form_builder)
4
+ value = form_builder.object.new_record? ? "1" : "false"
5
+ klass = form_builder.object.class.name.underscore
6
+ form_builder.hidden_field(:_destroy, {:value=>value, "data-remove"=>klass}) +
7
+ link_to(name, options={}, html_options={"href"=>"#", "class"=>"remove-child-link", :tabindex=> "0"})
8
+ end
9
+
10
+ def add_child_link(name, child, form_builder, options={})
11
+ # puts "||#{form_builder}||"
12
+ new_form = new_child_fields(child, form_builder, options)
13
+ raw(content_tag(:div, new_form, {:id=>"#{child}_template", :class=>"form-template"}, escape=false))+
14
+ link_to(name, options={}, html_options={"href"=>"#", "class"=>"add-child-link", "data-class-name"=>child})
15
+ end
16
+
17
+ def new_child_fields(child, form_builder, options={})
18
+ partial = options[:partial] ||= child.underscore
19
+ output = ""
20
+ form_builder.fields_for(child.pluralize.to_sym, child.camelize.constantize.new, :child_index => "__#{child}_id__") do |f|
21
+ output += render(:partial => partial, :locals => { :f => f })
22
+ end
23
+ output
24
+ end
25
+
26
+ def tfwac(f, field, controller, opts={})
27
+ opts["data-auto-complete"]='tf'
28
+ opts["data-auto-complete-url"]=eval("#{controller.to_s.underscore.tableize}_path(:format=>:json)")
29
+ f.text_field field, opts
30
+ end
31
+
32
+ def text_area_with_auto_complete(f, field, controller, opts={})
33
+ opts["data-auto-complete"]='ta'
34
+ opts["data-auto-complete-url"]=eval("#{controller.to_s.underscore.tableize}_path(:format=>:json)")
35
+ f.text_area field, opts
36
+ end
37
+ end
38
+ end
39
+
@@ -0,0 +1,113 @@
1
+ module AnafHabtm
2
+ class StringReader
3
+ KEY_SYMPTOM = "*"
4
+ POSS_SYMPTOM = "-"
5
+ START_COMMENT = "{"
6
+ ONE_LINE_COMMENT = "/"
7
+ END_COMMENT = "}"
8
+ NEWLINE = "\n"
9
+
10
+ DELIM = [START_COMMENT, NEWLINE, ONE_LINE_COMMENT, END_COMMENT]
11
+
12
+ MULTI_LINE = :multi_line
13
+ ONE_LINE = :one_line
14
+ NAME = :name
15
+ COMMENT = [MULTI_LINE, ONE_LINE]
16
+
17
+ @item = ""
18
+ @comment = nil
19
+ @items = []
20
+
21
+ def save(block)
22
+ unless @item.strip.empty?
23
+ @items << block.call(@item.strip, @comment.nil? ? nil : @comment.strip)
24
+ end
25
+ @item = ""
26
+ @comment = nil
27
+ end
28
+
29
+ def write_items(coll, &block)
30
+ lines = []
31
+ coll.each do |obj|
32
+ item, comment = block.call(obj)
33
+ if comment.nil? || comment.empty?
34
+ lines << item
35
+ elsif comment.index("/") || comment.index("\n")
36
+ lines << "#{item} {#{comment}}"
37
+ else
38
+ lines << "#{item} / #{comment}"
39
+ end
40
+ end
41
+ lines.join("\n")
42
+ end
43
+
44
+ def read_items(str, &block)
45
+ @items = []
46
+ buffer = ""
47
+ @item = ""
48
+ @comment = nil
49
+ state = NAME
50
+
51
+ str.chars.each do |char|
52
+ if (char == "/") && (state != MULTI_LINE)
53
+ @item = buffer.strip
54
+ buffer = ""
55
+ state = ONE_LINE
56
+ elsif char == "{"
57
+ @item = buffer.strip
58
+ buffer = ""
59
+ state = MULTI_LINE
60
+ elsif char == "}"
61
+ @comment = buffer.strip unless buffer.strip.empty?
62
+ buffer = ""
63
+ save(block)
64
+ state = NAME
65
+ elsif char == "\n"
66
+ if state == NAME
67
+ @item = buffer.strip
68
+ buffer = ""
69
+ save(block)
70
+ elsif state == ONE_LINE
71
+ @comment = buffer.strip
72
+ state = NAME
73
+ buffer = ""
74
+ save(block)
75
+ else
76
+ buffer << char
77
+ end
78
+ else
79
+ buffer << char
80
+ end
81
+ end
82
+
83
+ if state == ONE_LINE
84
+ @comment = buffer
85
+ elsif state == MULTI_LINE
86
+ @comment = buffer
87
+ else
88
+ @item = buffer
89
+ end
90
+ save(block)
91
+ @items
92
+ end
93
+
94
+ def self.parse_symptom(obj, symptom)
95
+ if symptom.index(KEY_SYMPTOM) == 0
96
+ obj.key_symptom = true
97
+ obj.symptom_name = symptom[KEY_SYMPTOM.length..symptom.length]
98
+ elsif symptom.index(POSS_SYMPTOM) == 0
99
+ obj.maybe = true
100
+ obj.symptom_name = symptom[POSS_SYMPTOM.length..symptom.length]
101
+ else
102
+ obj.symptom_name = symptom
103
+ end
104
+ end
105
+
106
+ def self.decorate_symptom(obj)
107
+ decorator = ""
108
+ decorator = KEY_SYMPTOM if obj.key_symptom
109
+ decorator = POSS_SYMPTOM if obj.maybe
110
+ "#{decorator}#{obj.symptom_name}"
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,11 @@
1
+ require 'rails/generators'
2
+
3
+ class AnafHabtmGenerator < Rails::Generators::Base
4
+ self.source_root File.expand_path("assets", File.dirname(__FILE__))
5
+
6
+ def copy_initializer_file
7
+ copy_file "nested_attributes.js", "public/javascripts/nested_attributes.js"
8
+ copy_file "nested_attributes.css", "public/stylesheets/nested_attributes.css"
9
+ end
10
+ end
11
+
@@ -0,0 +1,3 @@
1
+
2
+ .form-template {
3
+ display: none; }
@@ -0,0 +1,73 @@
1
+
2
+ function setUpDocument($jq) {
3
+ $jq.find("input[data-auto-complete|=tf]").each( function(idx, el){
4
+ $(el).autocomplete({
5
+ source: $(el).attr('data-auto-complete-url'),
6
+ minLength: 2
7
+ });
8
+ });
9
+
10
+ $jq.find("textarea[data-auto-complete|=ta]").each( function(idx, el){
11
+ setTextAreaAutoComplete($(el));
12
+ });
13
+
14
+ $jq.find("a.add-child-link").click( function() {
15
+ klass = $(this).attr('data-class-name');
16
+ $el = $(this).prev().children().first().clone();
17
+ new_id=new Date().getTime()
18
+ $el.html($el.html().replace(new RegExp('__'+klass+'_id__', 'g'), new_id));
19
+ $el.find('input[data-remove|='+klass+']').attr('value', 'false');
20
+ $(this).closest('.child').find('.'+klass+'_children').first()
21
+ .append($el).show();
22
+ setUpDocument($el);
23
+ return false;
24
+ });
25
+
26
+ $jq.find('a.remove-child-link').click( function() {
27
+ $(this).prev('input[type|=hidden]').val('1');
28
+ $(this).closest('.child').hide();
29
+ return false;
30
+ });
31
+ }
32
+
33
+ $(function () {
34
+ setUpDocument($("body"));
35
+
36
+ });
37
+ var text_area_delimiter = '\n';
38
+ function split(val) {
39
+ return val.split(new RegExp(text_area_delimiter+'\s*'));
40
+ }
41
+ function extractLast(term) {
42
+ return split(term).pop();
43
+ }
44
+ function setTextAreaAutoComplete($el) {
45
+ $el.autocomplete({
46
+ source: function(request, response) {
47
+ $.getJSON($el.attr('data-auto-complete-url'), {
48
+ term: extractLast(request.term)
49
+ }, response);
50
+ },
51
+ search: function() {
52
+ // custom minLength
53
+ var term = extractLast(this.value);
54
+ if (term.length < 2) {
55
+ return false;
56
+ }
57
+ },
58
+ focus: function() {
59
+ // prevent value inserted on focus
60
+ return false;
61
+ },
62
+ select: function(event, ui) {
63
+ var terms = split( this.value );
64
+ terms.pop(); // remove the current input
65
+ terms.push( ui.item.value ); // add the selected item
66
+ // add placeholder to get the comma-and-space at the end
67
+ // terms.push("");
68
+ this.value = terms.join(text_area_delimiter);
69
+ return false;
70
+ }
71
+ });
72
+ }
73
+
@@ -0,0 +1,8 @@
1
+ require 'test_helper'
2
+
3
+ class AnafHabtmTest < ActiveSupport::TestCase
4
+ # Replace this with your real tests.
5
+ test "the truth" do
6
+ assert true
7
+ end
8
+ end
@@ -0,0 +1,3 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'active_support'
data/uninstall.rb ADDED
@@ -0,0 +1 @@
1
+ # Uninstall hook code here
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: casey_jones
3
+ version: !ruby/object:Gem::Version
4
+ hash: 217
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 99
10
+ version: 0.0.99
11
+ platform: ruby
12
+ authors:
13
+ - Tyler Gannon
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-07-21 00:00:00 -07:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: some extra stuff for rails apps
23
+ email: t--g__a--nnon@gmail.com
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files:
29
+ - README
30
+ files:
31
+ - Gemfile
32
+ - README
33
+ - Rakefile
34
+ - install.rb
35
+ - lib/acts_as_linkable/acts_as_linkable.rb
36
+ - lib/ajax_loading/ajax_loading.rb
37
+ - lib/ajax_loading/controller_resource.rb
38
+ - lib/anaf_active_record.rb
39
+ - lib/casey_jones.rb
40
+ - lib/casey_jones/active_record_extensions.rb
41
+ - lib/casey_jones/application_helper_methods.rb
42
+ - lib/casey_jones/string_reader.rb
43
+ - lib/generators/anaf_habtm/anaf_habtm_generator.rb
44
+ - lib/generators/anaf_habtm/assets/nested_attributes.css
45
+ - lib/generators/anaf_habtm/assets/nested_attributes.js
46
+ - test/anaf_habtm_test.rb
47
+ - test/test_helper.rb
48
+ - uninstall.rb
49
+ has_rdoc: true
50
+ homepage: http://github.com/tylergannon/anaf_habtm
51
+ licenses: []
52
+
53
+ post_install_message:
54
+ rdoc_options:
55
+ - --charset=UTF-8
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ hash: 3
64
+ segments:
65
+ - 0
66
+ version: "0"
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ hash: 3
73
+ segments:
74
+ - 0
75
+ version: "0"
76
+ requirements: []
77
+
78
+ rubyforge_project:
79
+ rubygems_version: 1.3.7
80
+ signing_key:
81
+ specification_version: 3
82
+ summary: My favorite rails goodies all in one
83
+ test_files:
84
+ - test/anaf_habtm_test.rb
85
+ - test/test_helper.rb