anaf_habtm 0.0.82 → 0.0.83
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -1
- data/anaf_habtm.gemspec +6 -5
- data/lib/anaf_habtm/anaf_active_record.rb +159 -0
- data/lib/anaf_habtm/string_reader.rb +113 -0
- data/lib/anaf_habtm.rb +4 -3
- metadata +8 -7
- data/lib/anaf_active_record.rb +0 -44
- /data/lib/{application_helper_methods.rb → anaf_habtm/application_helper_methods.rb} +0 -0
- /data/lib/{hash.rb → anaf_habtm/hash.rb} +0 -0
data/Rakefile
CHANGED
data/anaf_habtm.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{anaf_habtm}
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.83"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Tyler Gannon"]
|
12
|
-
s.date = %q{2010-07-
|
12
|
+
s.date = %q{2010-07-12}
|
13
13
|
s.description = %q{accepts_nested_attributes_for habtm}
|
14
14
|
s.email = %q{t--g__a--nnon@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -21,12 +21,13 @@ Gem::Specification.new do |s|
|
|
21
21
|
"Rakefile",
|
22
22
|
"anaf_habtm.gemspec",
|
23
23
|
"install.rb",
|
24
|
-
"lib/anaf_active_record.rb",
|
25
24
|
"lib/anaf_habtm.rb",
|
26
|
-
"lib/
|
25
|
+
"lib/anaf_habtm/anaf_active_record.rb",
|
26
|
+
"lib/anaf_habtm/application_helper_methods.rb",
|
27
|
+
"lib/anaf_habtm/hash.rb",
|
28
|
+
"lib/anaf_habtm/string_reader.rb",
|
27
29
|
"lib/generators/anaf_habtm/anaf_habtm_generator.rb",
|
28
30
|
"lib/generators/anaf_habtm/assets/nested_attributes.js",
|
29
|
-
"lib/hash.rb",
|
30
31
|
"rails/init.rb",
|
31
32
|
"test/anaf_habtm_test.rb",
|
32
33
|
"test/test_helper.rb",
|
@@ -0,0 +1,159 @@
|
|
1
|
+
|
2
|
+
module AnafHabtm
|
3
|
+
module ActiveRecord
|
4
|
+
# options = {:named=>"name",
|
5
|
+
# :ar_options=>{:autosave=>true}}
|
6
|
+
def anaf_habtm(association, options={}, &block)
|
7
|
+
raise "Must specify :find or a code block." if (block.nil? && !options.has_key?(:find) && !options[:create])
|
8
|
+
class_eval do
|
9
|
+
# Define a proc that will look up the (potentially) existing object
|
10
|
+
finder = proc {|id| association.to_s.singularize.camelize.constantize.where(:id=>id).first
|
11
|
+
}
|
12
|
+
|
13
|
+
# Define a proc that will set the association collection
|
14
|
+
set_collection = proc {|me, coll| me.send("#{association.to_s.tableize}=", coll)}
|
15
|
+
has_and_belongs_to_many association.to_sym, options[:ar_options]||={}
|
16
|
+
# Define the actual association setter.
|
17
|
+
define_method "#{association.to_s.tableize}_attributes=", lambda{|attributes_for_association|
|
18
|
+
coll = []
|
19
|
+
klass = association.to_s.singularize.camelize.constantize
|
20
|
+
attributes_for_association.each_value do |params|
|
21
|
+
next if params["_destroy"] == "1"
|
22
|
+
obj = finder.call(params["id"]) if params.has_key?("id")
|
23
|
+
params.extend(AnafHabtm::HashExtension)
|
24
|
+
params_copy = params.copy_without_destroy
|
25
|
+
# ActiveRecord::Base.attributes=() doesn't like extra parameters.
|
26
|
+
if block.nil?
|
27
|
+
unless obj
|
28
|
+
srch = klass
|
29
|
+
options[:find].each do |scope, name|
|
30
|
+
if name.class==Hash
|
31
|
+
srch = klass.send(scope, params[name.first[0].to_s][name.first[1].to_s])
|
32
|
+
else
|
33
|
+
srch = klass.send(scope, params[name.to_s])
|
34
|
+
end
|
35
|
+
obj = srch.first
|
36
|
+
end
|
37
|
+
obj = obj ||= klass.new if options[:create]
|
38
|
+
|
39
|
+
unless obj
|
40
|
+
raise "Couldn't find or create #{association} named #{name}."
|
41
|
+
end
|
42
|
+
end
|
43
|
+
obj.attributes = params_copy
|
44
|
+
obj.save
|
45
|
+
coll << obj
|
46
|
+
else
|
47
|
+
coll << block.call(params_copy, obj)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
set_collection.call(self, coll)
|
51
|
+
}
|
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
|
@@ -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
|
data/lib/anaf_habtm.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
-
require 'hash'
|
2
|
-
require 'anaf_active_record'
|
3
|
-
require 'application_helper_methods'
|
1
|
+
require 'anaf_habtm/hash'
|
2
|
+
require 'anaf_habtm/anaf_active_record'
|
3
|
+
require 'anaf_habtm/application_helper_methods'
|
4
|
+
require 'anaf_habtm/string_reader'
|
4
5
|
ActiveRecord::Base.extend(AnafHabtm::ActiveRecord)
|
5
6
|
ActionView::Base.send :include, AnafHabtm::ApplicationHelperMethods
|
6
7
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: anaf_habtm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 185
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 83
|
10
|
+
version: 0.0.83
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Tyler Gannon
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-07-
|
18
|
+
date: 2010-07-12 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|
@@ -33,12 +33,13 @@ files:
|
|
33
33
|
- Rakefile
|
34
34
|
- anaf_habtm.gemspec
|
35
35
|
- install.rb
|
36
|
-
- lib/anaf_active_record.rb
|
37
36
|
- lib/anaf_habtm.rb
|
38
|
-
- lib/
|
37
|
+
- lib/anaf_habtm/anaf_active_record.rb
|
38
|
+
- lib/anaf_habtm/application_helper_methods.rb
|
39
|
+
- lib/anaf_habtm/hash.rb
|
40
|
+
- lib/anaf_habtm/string_reader.rb
|
39
41
|
- lib/generators/anaf_habtm/anaf_habtm_generator.rb
|
40
42
|
- lib/generators/anaf_habtm/assets/nested_attributes.js
|
41
|
-
- lib/hash.rb
|
42
43
|
- rails/init.rb
|
43
44
|
- test/anaf_habtm_test.rb
|
44
45
|
- test/test_helper.rb
|
data/lib/anaf_active_record.rb
DELETED
@@ -1,44 +0,0 @@
|
|
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
|
File without changes
|
File without changes
|