validatable_associations 0.1.1 → 0.2.0
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/VERSION +1 -1
- data/init.rb +6 -0
- data/lib/validatable_associations.rb +17 -85
- data/lib/validatable_associations/association.rb +58 -0
- data/lib/validatable_associations/confirmation.rb +29 -0
- data/lib/validatable_associations/has_one.rb +18 -0
- data/lib/validatable_associations/mass_assignment.rb +31 -0
- metadata +6 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/init.rb
CHANGED
@@ -4,114 +4,46 @@
|
|
4
4
|
# library. This add-on lets you specify associations to other validatable Classes
|
5
5
|
# and allows you to set up a decent validatable structure.
|
6
6
|
module ValidatableAssociations
|
7
|
+
include MassAssignment
|
8
|
+
include Association
|
9
|
+
include Confirmation
|
7
10
|
|
8
11
|
# ValidatableAssociations::ClassMethods
|
9
12
|
#
|
10
|
-
# Includes Class methods
|
13
|
+
# Includes Class methods from associations.
|
11
14
|
module ClassMethods
|
12
|
-
|
13
|
-
# Reader/writer method for has_one associations. Sets 1-n +associations+
|
14
|
-
# or defaults to return all previously specified associations if no
|
15
|
-
# parameters were given.
|
16
|
-
def has_one(*associations)
|
17
|
-
@has_one = [] unless @has_one
|
18
|
-
return @has_one if associations.empty?
|
19
|
-
@has_one += associations.map { |association| association.to_s }
|
20
|
-
end
|
21
|
-
|
15
|
+
include ValidatableAssociations::HasOne::ClassMethods
|
22
16
|
end
|
23
17
|
|
24
18
|
def self.included(base) #:nodoc:
|
25
19
|
base.extend(ClassMethods)
|
26
20
|
end
|
27
21
|
|
28
|
-
# The initialize method handles mass-assignment of a given Hash of
|
29
|
-
# +attributes+ to their instance variables.
|
30
|
-
def initialize(attributes = {})
|
31
|
-
return if !attributes || attributes.empty?
|
32
|
-
attributes.each { |ivar, value| assign_to(ivar, value) }
|
33
|
-
end
|
34
|
-
|
35
22
|
# Catches calls to undefined methods. Checks if the +method+ called matches
|
36
23
|
# a reader/writer method of an association and handles the read/write process.
|
37
24
|
# Delegates to super otherwise.
|
38
25
|
def method_missing(method, *args)
|
39
|
-
|
40
|
-
super unless self.class.has_one.include? association_name
|
26
|
+
method = clean_method_name(method)
|
41
27
|
|
42
|
-
|
43
|
-
|
44
|
-
|
28
|
+
if association? method
|
29
|
+
handle_association(method, args[0])
|
30
|
+
elsif confirmation? method
|
31
|
+
handle_confirmation(method, args[0])
|
32
|
+
else
|
33
|
+
super
|
34
|
+
end
|
45
35
|
rescue NameError
|
46
36
|
super
|
47
37
|
end
|
48
38
|
|
49
|
-
# Returns whether the validations of this model and all associated models
|
50
|
-
# passed successfully.
|
51
|
-
def valid?
|
52
|
-
validate_associations
|
53
|
-
super && associations_valid?
|
54
|
-
end
|
55
|
-
|
56
39
|
private
|
57
40
|
|
58
|
-
# Assigns a given +value+ to a given +ivar+. Tries to use the writer method
|
59
|
-
# for the given instance variable and defaults to setting it directly in case
|
60
|
-
# no writer method was found.
|
61
|
-
def assign_to(ivar, value)
|
62
|
-
if assign_via_writer? ivar
|
63
|
-
self.send("#{ivar}=", value)
|
64
|
-
else
|
65
|
-
self.instance_variable_set("@#{ivar}", value)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
# Checks whether a given +ivar+ should be assigned via an existing writer
|
70
|
-
# method or directly.
|
71
|
-
def assign_via_writer?(ivar)
|
72
|
-
self.methods.include?("#{ivar}=") || self.class.has_one.include?(ivar)
|
73
|
-
end
|
74
|
-
|
75
|
-
# Takes an +association_name+ and returns an existing association matching
|
76
|
-
# the given name. Instantiates a new association in case it hasn't been
|
77
|
-
# initialized already or in case of given +arguments+.
|
78
|
-
def find_or_create_association(association_name, arguments = nil)
|
79
|
-
if arguments
|
80
|
-
constant_from(association_name).new arguments
|
81
|
-
else
|
82
|
-
association = self.instance_variable_get("@#{association_name}")
|
83
|
-
association = constant_from(association_name).new unless association
|
84
|
-
association
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
# Validates all models associated with this model and stores the results.
|
89
|
-
def validate_associations
|
90
|
-
@association_validity = self.class.has_one.map do |association|
|
91
|
-
self.send(association).valid?
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
# Returns whether the validations of all models associated with this model
|
96
|
-
# passed successfully.
|
97
|
-
def associations_valid?
|
98
|
-
!@association_validity.include?(false)
|
99
|
-
end
|
100
|
-
|
101
41
|
# Expects the name of a reader/writer +method+ and turns it into a valid
|
102
42
|
# name for an association.
|
103
|
-
def
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
end
|
108
|
-
|
109
|
-
# Converts a given +symbol+ from snake_case into an existing Constant.
|
110
|
-
# Note that the constanize method might raise a NameError in case the given
|
111
|
-
# symbol could not be mapped to a Constant.
|
112
|
-
def constant_from(symbol)
|
113
|
-
symbol.to_s.camelize.constantize
|
43
|
+
def clean_method_name(method)
|
44
|
+
name = method.to_s
|
45
|
+
name.slice! -1 if name[-1, 1] == "="
|
46
|
+
name
|
114
47
|
end
|
115
48
|
|
116
49
|
end
|
117
|
-
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module ValidatableAssociations
|
2
|
+
module Association
|
3
|
+
|
4
|
+
# Returns whether the validations of this model and all associated models
|
5
|
+
# passed successfully.
|
6
|
+
def valid?
|
7
|
+
validate_associations
|
8
|
+
super && associations_valid?
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
# Validates all models associated with this model and stores the results.
|
14
|
+
def validate_associations
|
15
|
+
@association_validity = self.class.has_one.map do |association|
|
16
|
+
self.send(association).valid?
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns whether the validations of all models associated with this model
|
21
|
+
# passed successfully.
|
22
|
+
def associations_valid?
|
23
|
+
!@association_validity.include? false
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns whether a given +method_name+ matches an association.
|
27
|
+
def association?(method_name)
|
28
|
+
self.class.has_one.include? method_name
|
29
|
+
end
|
30
|
+
|
31
|
+
def handle_association(association_name, argument)
|
32
|
+
association_to_set = find_or_create_association(association_name, argument)
|
33
|
+
self.instance_variable_set("@#{association_name}", association_to_set)
|
34
|
+
association_to_set
|
35
|
+
end
|
36
|
+
|
37
|
+
# Takes an +association_name+ and returns an existing association matching
|
38
|
+
# the given name. Instantiates a new association in case it hasn't been
|
39
|
+
# initialized already or in case of given +arguments+.
|
40
|
+
def find_or_create_association(association_name, arguments = nil)
|
41
|
+
if arguments
|
42
|
+
constant_from(association_name).new arguments
|
43
|
+
else
|
44
|
+
association = self.instance_variable_get("@#{association_name}")
|
45
|
+
association = constant_from(association_name).new unless association
|
46
|
+
association
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Converts a given +symbol+ from snake_case into an existing Constant.
|
51
|
+
# Note that the constanize method might raise a NameError in case the given
|
52
|
+
# symbol could not be mapped to a Constant.
|
53
|
+
def constant_from(symbol)
|
54
|
+
symbol.to_s.camelize.constantize
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module ValidatableAssociations
|
2
|
+
module Confirmation
|
3
|
+
|
4
|
+
private
|
5
|
+
|
6
|
+
def confirmation?(method_name)
|
7
|
+
if method_name[-13, 13] == "_confirmation"
|
8
|
+
method = method_name.dup
|
9
|
+
method.slice!(-13, 13)
|
10
|
+
else
|
11
|
+
method = method_name
|
12
|
+
end
|
13
|
+
|
14
|
+
self.public_methods.include? method
|
15
|
+
end
|
16
|
+
|
17
|
+
def handle_confirmation(confirmation, argument)
|
18
|
+
return self.instance_variable_get("@#{confirmation}") unless argument
|
19
|
+
|
20
|
+
if self.public_methods.include? "#{confirmation}="
|
21
|
+
self.send("#{confirmation}=", argument)
|
22
|
+
else
|
23
|
+
self.instance_variable_set("@#{confirmation}", argument)
|
24
|
+
end
|
25
|
+
argument
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module ValidatableAssociations
|
2
|
+
module HasOne
|
3
|
+
|
4
|
+
module ClassMethods
|
5
|
+
|
6
|
+
# Reader/writer method for has_one associations. Sets 1-n +associations+
|
7
|
+
# or defaults to return all previously specified associations if no
|
8
|
+
# parameters were given.
|
9
|
+
def has_one(*associations)
|
10
|
+
@has_one = [] unless @has_one
|
11
|
+
return @has_one if associations.empty?
|
12
|
+
@has_one += associations.map { |association| association.to_s }
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module ValidatableAssociations
|
2
|
+
module MassAssignment
|
3
|
+
|
4
|
+
# The initialize method handles mass-assignment of a given Hash of
|
5
|
+
# +attributes+ to their instance variables.
|
6
|
+
def initialize(attributes = {})
|
7
|
+
return if !attributes || attributes.empty?
|
8
|
+
attributes.each { |ivar, value| assign_to(ivar, value) }
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
# Assigns a given +value+ to a given +ivar+. Tries to use the writer method
|
14
|
+
# for the given instance variable and defaults to setting it directly in case
|
15
|
+
# no writer method was found.
|
16
|
+
def assign_to(ivar, value)
|
17
|
+
if assign_via_writer? ivar
|
18
|
+
self.send("#{ivar}=", value)
|
19
|
+
else
|
20
|
+
self.instance_variable_set("@#{ivar}", value)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Checks whether a given +ivar+ should be assigned via an existing writer
|
25
|
+
# method or directly.
|
26
|
+
def assign_via_writer?(ivar)
|
27
|
+
self.methods.include?("#{ivar}=") || association?(ivar)
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: validatable_associations
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Harrington
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-10-
|
12
|
+
date: 2009-10-25 00:00:00 +02:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -46,6 +46,10 @@ files:
|
|
46
46
|
- VERSION
|
47
47
|
- init.rb
|
48
48
|
- lib/validatable_associations.rb
|
49
|
+
- lib/validatable_associations/association.rb
|
50
|
+
- lib/validatable_associations/confirmation.rb
|
51
|
+
- lib/validatable_associations/has_one.rb
|
52
|
+
- lib/validatable_associations/mass_assignment.rb
|
49
53
|
- spec/lib/validatable_associations_spec.rb
|
50
54
|
- spec/spec_helper.rb
|
51
55
|
has_rdoc: true
|